1、分类
File只能对文件进行处理,如果想要处理文件里的内容,则要使用文件流。
文件流可分为字符和字节流:
- 字节流(可读写任何格式的文件)
- inputStream(抽象父类)
- FileInputStream
- outputStream(抽象父类)
- FileOutputStream
- inputStream(抽象父类)
- 字符流(可续写记事本打开看得懂的文件)
- Reader(抽象父类)
- FileReader
- Writer(抽象父类)
- FileWriter
- Reader(抽象父类)
2、字节流具体操作
写文件
- 各个操作系统的换行符不一样,Mac:\r Windows: \r\n Linux:\n
FileOutputStream fos = new FileOutputStream("src/test/java/test.txt",true);
//把要写入的东西放在数组里
String str = "我要写入文件的东西";
byte[] bytes = str.getBytes();
fos.write(bytes);
fos.close();
读文件
- 读到末位文件,返回的是-1
- fis.read()执行一次,相当于移动一次光标,注意不要重复读
FileInputStream fis = new FileInputStream("src/test/java/test.txt");
int b;
while ((b = fis.read()) != -1){
System.out.print((char)b);
}
fis.close();
拷贝文件
边读边写,一次读写一个字节(速度极慢)
FileInputStream fis = new FileInputStream("src/test/java/test.txt");
FileOutputStream fos = new FileOutputStream("src/test/java/test1.txt");
int b ;
while ((b = fis.read()) != -1){
fos.write(b);
}
fos.close();
fis.close();
一次读写多个字节数据,快
- 读取的时候,可以一次读取一个字节数组的长度
- 写入的时候,使用fos.write(bytes,0,len)的写入方法,表示从bytes数组中的0下标位置向后,写len长度的字节,而len长度表示这次我读取的字节数,所以最后一次读取的时候不会出现错误,多写(因为读了几个就写几个)。
FileInputStream fis = new FileInputStream("src/test/java/test.txt");
FileOutputStream fos = new FileOutputStream("src/test/java/test1.txt");
int len ;
byte[] bytes = new byte[2];
while ((len = fis.read(bytes)) != -1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
3、字符流具体操作
读文件
- 一次读取char[2]哥字符的数组,读完以后存在chars中,len表示这次读取了几个字符
FileReader fileReader = new FileReader("src/test/java/test.txt");
int len ;
char[] chars = new char[2];
while ((len = fileReader.read(chars)) != -1){
System.out.print(chars);
}
fileReader.close();
写文件
FileWriter fileWriter = new FileWriter("src/test/java/test.txt",true);
String str = "我要追加的字符串";
fileWriter.write(str);
fileWriter.write(str.toCharArray());
fileWriter.close();
原理
字节流没有缓冲区
读取时候的缓冲区
字符流存在一个缓冲区,第一次读的时候会尽可能的多读一些数据(8192长度),存放在缓冲区,然后先从缓冲区拿,拿完了再向文件中取。
写入时候的缓冲区
字符流在写入的时候,其实是写入到一个缓冲区中,缓冲区存满了才往硬盘里导入,可以使用flush()方法刷新缓冲区
4、缓冲流
高级流是对基本流做了一个包装,底层真正读写数据的其实还是基本流。
高级流的构造函数都要拿基本流作为传入参数,来构造
缓冲流(高效)
字节缓冲流
使用缓冲流来拷贝文件
- 使用方法其实还是一样的
- 不用关闭基本流
- 之所以快,是因为它节省了和硬盘打交道的时间(一次读很多),读完以后放到缓冲区中(缓冲区在内存中,搬运速度就很快)
字符缓冲流
字符缓冲读取文件
字符缓冲写入文件
5、转换流
字符流和字节流之间的桥梁。可以相互转换
6、序列化流
将对象写入文件中
- 构造函数里要传入基本流FileOutputStream
- 对象需要有Serializable接口
Student student = new Student();
student.setName("张三");
student.setAge(18);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("src/test/java/test.txt"));
objectOutputStream.writeObject(student);
objectOutputStream.close();
读取文件中的对象
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("src/test/java/test.txt"));
Object o = objectInputStream.readObject();
System.out.println(o);
objectInputStream.close();
原理
序列化以后会的到版本号,不相同的话反序列化会报错。
可以自己手动在对象中定义版本号,名字不能改!一定要用这个名字!
- 如果有成员变量不想序列化,就在前面加transient
如果文件中有多个对象怎么办呢?
写入多个对象
读取多个对象
一次 readObject() 只能读取一个对象,我们一般都把对象放在一个list当中,直接读取这个list
7、打印流
打印流不能读,只能写
- 字节打印流:PrintStream
- 字符打印流:PrintWriter
- 有三个特点:
- 只有写,没有读
- 有特有的方法,可以把数据原样写出
- 特有的写出方法可以实现自动刷新,自动换行(打印一次数据=写出+换行+刷新)
字节打印流
无缓冲区
PrintStream printStream = new PrintStream(new FileOutputStream("src/test/java/test.txt"));
printStream.println(97);
printStream.println(true);
printStream.close();
字符打印流
有缓冲区,想刷新要自动开启
PrintWriter printWriter = new PrintWriter(new FileWriter("src/test/java/test.txt"));
printWriter.println("wdafawdaw");
printWriter.close();
其实用的就是打印流
System.out.println();