目录
文件专属
FileInputStream(掌握)
1.文件字节输入流,万能的,任何类型的文件都可以采用这个流来读
2.字节的方式,完成输入操作,完成读的操作(硬盘---->内存)
fis = new FileInputStream("D:\\Note\\111.txt");
文件字节输入流,负责写(从硬盘到内存)
从磁盘的路径即磁盘中去读取数据到内存中,输入流。(就是我我们电脑磁盘中的.txt文件解析成流的形式读取到内存就是我们写代码的地方,然后对内存中的数据进行处理)
package IO流;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
java.io.FileInputStream
1.文件字节输入流,万能的,任何类型的文件都可以采用这个流来读
2.字节的方式,完成输入操作,完成读的操作(硬盘---->内存)
*/
public class FileInputTest01 {
public static void main(String[] args) {
FileInputStream fis = null;
//创建文件字节流文件
//以下都是采用了绝对路径的方式
//文件路径:D:\Note\111.txt 会制动把\变化为\\,因为java中的\代表转义
try {
fis = new FileInputStream("D:\\Note\\111.txt");
int readData = fis.read();
System.out.println(readData);//这个方法的返回值是:读取到的字节本身
readData = fis.read();
System.out.println(readData);
readData = fis.read();
System.out.println(readData);
readData = fis.read();
System.out.println(readData);
readData = fis.read();
System.out.println(readData);//读取到末尾了,返回值为-1
//文件中为:abcd
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
//finally语句块中确保流一定关闭。流是null的时候没必要关闭,避免空指针异常
if (fis!=null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
读取到末尾了,再次读就读取不到数据就返回-1。
对程序进行改造,while循环
package IO流;
import java.io.FileInputStream;
import java.io.IOException;
/**
*对第一个程序进行改进,循环方式
*一次读取一个字节,这样内存和硬盘交互太频繁了,基本上时间、资源都耗费了
*/
public class FileInputTest02 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\Note\\111.txt");
//while循环
int readDate = 0;
while((readDate = fis.read())!=-1){
System.out.println(readDate);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
但是一次读取一个字节,这样内存和硬盘交互太频繁了,基本上时间、资源都耗费了
再次进行改造,一次读取多个字节
int read(byte[] b)
一次最多读取b.length个字节 减少硬盘和内存的交互,提高程序的执行效率往byte[]数组当中读
package IO流;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputTest03 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
//使用相对路径
//IDEA当前的默认路径为,工程Project的根就是IDEA的默认当前路径
fis = new FileInputStream("D:\\Note\\111.txt"); //文件夹数据为abcdef
//开始读,采用byte数组,一次读取多个字节,最多读取“数组.length”个字节
byte[] bytes = new byte[4];//一次最多读取数组.length个字节,即在这个例子是4个字节
int readCount = fis.read(bytes);//4 返回值为读取的字节数量
System.out.println(readCount);
//不应该全部都转,应该是读取了多少个字节,转换多少个
System.out.println(new String(bytes,0,readCount));
readCount = fis.read(bytes);//2
System.out.println(readCount);
System.out.println(new String(bytes,0,readCount));
//最后读不到数据返回-1
readCount = fis.read(bytes);//-1
System.out.println(readCount);
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
1.文件夹数据为abcdef
2.第一次字节会读取数组的大小的数据即4个字节即abcd
3.但是文件夹中还有两个字节ef
如果使用new String(bytes)
4.该方法是把byte数组全部转换成了字符串
5.进行第二次读取时会把第一次的字节数进行覆盖即efcd
new String(bytes,0,readCount)可以进行解决全部转换的问题,如下
最后的改进
package IO流;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputTest04 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\Note\\111.txt");
//准备一个数组
byte[] bytes = new byte[4];
int readCount = 0;
while((readCount = fis.read(bytes))!= -1){
System.out.println(new String(bytes,0,readCount));
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
其他两个常用方法
int available() | 返回流当中剩余的没有读到的字节数量 |
long skip(long n) | 跳过几个字节不读 |
package IO流;
import java.io.FileInputStream;
import java.io.IOException;
public class FileInputTest05 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("D:\\Note\\111.txt");
byte[] bytes = new byte[fis.available()];
int readCount = fis.read(bytes);
// System.out.println(new String(bytes));
//跳过几个字节不读取,这个方法以后可能也会用到
fis.skip(3);
System.out.println(fis.read());
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fis!=null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
System.out.println("字节数量:" + fis.available());获取文件的字节数量
不需要循环了,直接读一次就可以,直接获取文件夹有多少字节数量
byte[] bytes = new byte[fis.available()];
注意:这种方式不太适合太大的文件,因为bytes[]数组不能太大
FileOutputStream(掌握)
-
文件不存在时会自动创建新的文件
-
第二个参数 此构造方法为重载方法这种方式需要谨慎使用,默认false,表示覆盖擦除原有内容, 写入后只包含新写入内容, 原有内容将会被覆盖不存保留 。因此他会把源文件清空
-
下面展示的代码为ture,表示在原有内容的基础上进行追加写入写内容,以追加的方式在文件末尾写入。不会清空源文件内。
-
写完一定要去刷新,让流在关闭的时候把还在通道里的数据强制完成。
文件字节输出流,负责写(从内存到硬盘)
package IO流;
import java.io.FileOutputStream;
import java.io.IOException;
public class FileOutputTest01 {
public static void main(String[] args) {
FileOutputStream fos = null;
try {
//文件不存在时会自动创建新的文件
//这种方式需要谨慎使用,因为他会把源文件清空
//以追加的方式在文件末尾写入。不会清空源文件内容
fos = new FileOutputStream("D:\\Note\\111.txt",true);
//开始往文件中写
byte[] bytes = {97,98,99,100};
//将byte数组全部写出
fos.write(bytes);//abcd
//将bytes数组的一部分写出
fos.write(bytes,0,2);//写出ab
String s= "china";
byte[] ss = s.getBytes();//将字符串转换为byte数组
fos.write(ss);
//写完之后一定要刷新
fos.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (fos != null)
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
把数据写入到磁盘,即内存到磁盘,持久化
文件的拷贝
使用Fileinput和FileOutput完成文件的拷贝
拷贝的过程应该是一边读一边写,
使用以上的字节流拷贝文件的时候,文件类型随意,万能的,什么样的文件都能拷贝
package IO流;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Copy1 {
public static void main(String[] args) {
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream("D:\\Note\\111.txt");
fos = new FileOutputStream("D:\\Note\\222.txt");
//最核心的一边读一边写
byte[] bytes = new byte[1024*1024];
int readCount = 0;
while((readCount = fis.read(bytes)) != -1){
fos.write(bytes,0,readCount);
}
//输出流最后要刷新
fos.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
if (fos != null)
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
if(fis != null)
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
把读取到的readCount = fis.read(bytes) 字节写入到对应的文件中
ByteArrayInputStream(掌握)
- FileInputStream、FileOutputStream、FileReader、FileWriter是存储在硬盘上的
- 硬盘上的资源java虚拟机是无权直接访问的,必须借助操作系统,java虚拟机借助完了之后要通知操作系统释放资源
- 把源头换成电脑上的一块内存(字节数组),既然是一块内存那么java就可以直接访问,因为是java虚拟机的一块内存。不用关闭(释放)
- 所有的东西都可以转成字节数组(字符串转成字节数组、任何一个数据(包括343434、包括3.1415926、包括一个一个的对象都可以转成字节数组))
- 文件可以无限制的往里面加内容,但是内存速度快、量小,所以内存(字节数组 byte[] )不允许不建议量特别的大
转成字节数组有什么好处?
字节数组就为二进制了,方便网络上进行传输
那如何解决呢,通过ByteArrayInputStream(byte[] buf)
参数为一个字节数组
创建一个 ByteArrayInputStream ,使其使用 buf作为其缓冲区数组
传对应的路径与字节数组创建对应的文件并把字节数组放进去
public static void writeBytesToFile(byte[] bs, String filePath) {
OutputStream out = null;
InputStream is = null;
try {
out = new FileOutputStream(filePath);
is = new ByteArrayInputStream(bs);
byte[] buff = new byte[bs.length];
int len = 0;
while ((len = is.read(buff)) != -1) {
out.write(buff, 0, len);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (null != is) {
is.close();
}
if (null != out) {
out.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
FileReader
文件字符输入流,只能读取普通文本。读取文本内容时,比较方便,快捷
package IO流;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest01 {
public static void main(String[] args) {
FileReader reader = null;
try {
reader = new FileReader("D:\\Note\\111.txt");
char[] chars = new char[4];//一次读取四个字符
reader.read(chars);
for (char c : chars){ //按照字符的方式读取,第一次a 第二次b 第三次 小
System.out.println(c);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if (reader!=null)
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
char[] chars = new char[4]; | byte[] bytes = new byte[4] |
FileWriter
文件字符输出流—写,只能输出普通文本
package IO流;
import java.io.FileWriter;
import java.io.IOException;
public class FileWriterTest01 {
public static void main(String[] args) {
FileWriter out = null;
try {
//创建文件字符输出流对象
out = new FileWriter("D:\\Note\\111.txt",true);
//开始写
char[] chars = {'1','x','3','小','七'};
out.write(chars);
out.write(chars,3,2);
out.write("\n");//换行
out.write("廿七小七");
//需要刷新
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (out != null)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
字符流拷贝普通文本文件
package IO流;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
/*
使用FileReader和FileWriter进拷贝的话,只能拷贝普通文本文件
*/
public class Copy2 {
public static void main(String[] args) {
FileReader in = null;
FileWriter out = null;
try {
in = new FileReader("D:\\Note\\111.txt");
out = new FileWriter("D:\\Note\\222.txt");
char[] chars = new char[1024 * 512];//1M
int readCount = 0;
while((readCount = in.read(chars))!= -1){
out.write(chars,0,readCount);
}
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(in!=null)
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
if(out!=null)
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
BufferedReader
带有缓冲区的字符输入流,使用这个流的时候不需要自定义char数组,或者说不需要自定义byte数组,自带缓冲
BufferedReader类从字符输入流中读取文本并缓冲字符,以便有效地读取字符,数组和行
可以通过构造函数指定缓冲区大小也可以使用默认大小。对于大多数用途,默认值足够大
由Reader构成的每个读取请求都会导致相应的读取请求由基础字符或字节流构成,建议通过BufferedReader包装Reader的实例类以提高效率如下:
BufferedReader in = new BufferedReader(new FileReader(“foo.in”));
现在有一个文档如下:
执行如下
package IO流;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class BuggeredReaderTest {
//字符缓冲流
public static void main(String[] args) {
FileReader fr = null; //字符输入流
BufferedReader buf = null; //带有缓存区的字符输入流
try{
fr = new FileReader("D:\\Note\\111.txt");
/**当一个流的构造方法中需要一个流的时候,这个被传进来的流叫做:节点流
* 外部负责包装的流,叫做包装流,还有一个名字叫做:处理流
* 像当前这个程序来说,FileReader就是一个节点流,BufferReader就是处理流
*/
buf = new BufferedReader(fr);
String s = null;
//readline方法读取文本的一行,但是不带换行符
while((s = buf.readLine())!=null){ // 没有读出来换行
System.out.println(s);
}
//关闭流
//对于包装流来说,只需要关闭包装流,里面的流会自动关闭
}catch (IOException e){
e.printStackTrace();
}finally {
if (buf != null){
try {
buf.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
}
打印如下:
abcdabchinaabcdabchinaabcdab
chinaabcdabchinaabcdabchina
注意:
1. readline方法读取文本的一行,但是不带换行符
2. 对于包装流来说,只需要关闭包装流或者说关闭处理流,里面的流会自动关闭
3. FileInputStream fileInputStream = new FileInputStream("file");
FileInputStream是一个字节流,不是一个字符流,BufferedReader里面需要传一个字符流
BufferedReader buf = new BufferedReader(fileInputStream);
fileInputStream是节点流,inputStreamReader是包装流
这需要进行转换把节点流转换成字符流在进行包装
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
将节点流转换为字符流
inputStreamReader是节点流,bufferedReader是包装流
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
package streamsIO;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
public class BufferReadTest01 {
public static void main(String[] args) throws Exception {
FileInputStream fileInputStream = new FileInputStream("file");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));
//合并
String line = null;
while((line = bufferedReader.readLine())!=null){
System.out.println(line);
}
//关闭,关闭最外层
bufferedReader.close();
}
}
BufferedWriter
带有缓冲的字符输出流
package IO流;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferWriterTest {
public static void main(String[] args) throws IOException {
BufferedWriter out = new BufferedWriter(new FileWriter("D:\\Note\\111.txt",true));
out.write("tde");
out.write("\n");
out.write("riegrghrhjo");
out.flush();
out.close();
}
}
PrintStream
setOut改变流的方向
标准的字节输出流。默认输出到控制台。
package IO流;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
public class PrintStreamTest {
public static void main(String[] args) throws FileNotFoundException {
System.out.println("hello word");
//分开写
PrintStream ps = System.out;
ps.println("hello l");
ps.println("hello l");
ps.println("hello a");
//标准输出流不需要手动关闭
//改变便准输出流的输出方向
//标准输出流不再指向控制台,指向我们的文件文件
PrintStream printStream= new PrintStream(new FileOutputStream("D:\\Note\\111.txt"));
System.setOut(printStream);
System.out.println("11");
System.out.println("222");
System.out.println("3333");
}
}
就是把我们打印的数据
System.setOut(printStream);
打印到我们的改变的文件里面。可以在我们日志工具类中使用
PrintStream printStream= new PrintStream(new FileOutputStream("D:\\Note\\111.txt"));
setIn()把文件里面的内容读到程序里
改变了当前应用的标准输入设备
package IO流;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Scanner;
public class Read {
public static void main(String[] args) {
try {
InputStream ps = new FileInputStream("D:\\Note\\111.txt");
System.setIn(ps);
Scanner scanner = new Scanner(System.in);
String line = "";
while (scanner.hasNextLine()) {
line = scanner.nextLine();
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
日志工具类的使用
package IO流;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public class LogUtil{
public static void log(String msg){
PrintStream out = null;
/*
记录日志的方法
*/
try {
out = new PrintStream(new FileOutputStream("D:\\Note\\111.txt",true));
//改变输出方向
System.setOut(out);
//日期当前时间
Date date = new Date();
//格式化
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
String strtime= sdf.format(date);
System.out.println(strtime + ":" + msg);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
package IO流;
public class LogTest {
public static void main(String[] args) {
//测试工具类是否好用
LogUtil.log("调用了System类的gc方法,建议启动垃圾回收器");
LogUtil.log("调用了UserService的doSome()方法");
LogUtil.log("用户尝试进行登录,验证失败");
}
}