一、概念
文件在程序中是以流的形式来操作的。
流:是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两个存储位置之间的传输称为流。流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
二、分类
1、按照流向划分:输入流、输出流
以内存为参照:
输入流:从文件流向内存
输出流:从内存流向文件
2、按照传输单位划分:字节流、字符流
字节流:可以用于读写二进制文件及任何类型文件。
字符流:可以用于读写文本文件。
以“Reader”结尾都是字符流,操作的都是字符型的数据;以“Stream”结尾的都是字节流,操作的都是byte数据。
三、字节流VS字符流的区别
字符流的由来: 因为数据编码的不同,从而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。
区别:
1、读写单位不同:字节流以字节(1 byte,1byte=8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
2、处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
3、缓存。字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件。
总结:优先选用字节流。因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。
四、实际使用
-
InputStream && OutputStream
在java中InputStream是字节输入流,用来将文件中的数据读取到java程序中。
outputStream 是字节输出流,用来将内存中的数据输出到文件中。
InputStream 和 OutputStream为各种输入输出字节流的基类,所有字节流都继承这两个基类。
图片.png Reader && Writer
字符流只能处理字符,不能用来处理 .jpg;.mp3;.mp4;.avi;.doc;.ppt等二进制文件,这些只能通过字节流来处理。所以对于纯文本的文件,强烈推荐使用字符输入输出流。
字符流的本质其实就是基于字节流在读取时去查了指定的码表。
Reader 和 Writer 为各种输入输出字符流的基类,所有字符流都继承这两个基类。
注意:如果字符输出流不调用close()方法关闭资源,数据只是保存到缓冲区,并不会保存到文件(这一点与FileOutputStream不同,即使它不调用close()方法依然会写入到文件中)。
这里就得介绍一下flush()这个方法。
flush()和close()方法的区别:
flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。
close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后再关闭流。流不可以使用。
- 文件操作流 --------- FileInputStream && FileOutputStream
//1.指定要读 的文件目录及名称
File file =new File("文件路径");
//2.创建文件读入流对象
FileInputStream fis =new FileInputStream(file);
//3.定义结束标志,可用字节数组读取
int i =0 ;
while((i = fis.read())!=-1){
//i 就是从文件中读取的字节,读完后返回-1
}
//4.关闭流
fis.close();
//5.处理异常
//1.指定要写到的文件目录及名称
File file =new File("文件路径");
//2.创建文件读入流对象
FileOutputStream fos =new FileOutputStream(file);
//3.定义结束标志
fos.write(要写出的字节或者字节数组);
//4.刷新和关闭流
fos.flush();
fos.close();
//5.处理异常
文件操作流 --------- FileReader && FileWriter
缓冲流 --------- BufferedInputStream && BufferedOutputStream
缓冲流是对流的操作的功能的加强,提高了数据的读写效率。既然缓冲流是对流的功能和读写效率的加强和提高,所以在创建缓冲流的对象时应该要传入要加强的流对象。缓冲流 --------- BufferedReader && BufferedWriter
在字符读入缓冲流BufferedReader 中还提供了读一行的方法 readLine() 可以读取一行文本
在字符写出缓冲流BufferedWriter 中还提供了写入一个行分隔符的方法writeLine(),用于写出时换行转换流 --------- InputStreamReader && OutputStreamWriter
InputStreamReader: 字符转换输出流
OutputStreamWriter:字符转换输入流
实际上,这两个类内部各自持有一个inputStream 和 outputStream对象,相当于是对inputStream 和 outputStream进行了包装,将输入字节流转换成字符流,便于读写操作。注 :要传入字节流作为参数
需求:读取键盘输入的一行文本,再将输入的写到本地磁盘上
//1.获取键盘输入的字节流对象in
InputStream in =Stream.in;
/*2.用转换流将字节流对象转换为字符流对象,方便调用字符缓冲流的readeLine()方法*/
InputStreamReader isr =new InputStreamReader(in);
/*5.创建字符转换输出流对象osw,方便把输入的字符流转换为字节输出到本地文件。*/
OutputStreamWriter osw =new OutputStreamWriter(new
FileOutputStream(new File("文件名")));
/*3.现在isr是字符流,可以作为参数传入字符缓冲流中*/
BufferedReader br =new BufferedReader(isr);
/*4.可以调用字符缓冲流br的readLine()方法度一行输入文本*/
String line =null;
while((line =br.readLine()){
osw.write(line);//osw是字符流对象,可以直接操作字符串
}
注:InputStreamReader isr =new InputStreamReader(new "各种类型的字节输入流都行即是:后缀为InputStream就行");
OutputStreamWriter osw =new OutputStreamWriter(new
"后缀为OutputStream就行");
- 对象流 --------- ObjectInputStream && ObjectOutputStream
不同于以上两种类型的流这里只能用字节对对象进行操作
ObjectOutputStream对象的序列化:
将java程序中的对象写到本地磁盘里用ObjectOutputStream
eg:将Person类的对象序列化到磁盘
1.创建Person类
注1:此类要实现Serializable接口,此接口为标志性接口
注2:此类要有无参的构造函数
注3:一旦序列化此类不能再修改
class Person implements Serializable{
public Person(){}
}
2.创建对象流对象
注:要增强功能可以将传入文件缓冲流
ObjectOutputStream oos =new ObjectOutputStream(
new FileOutputStream(new File("文件路径")));
3.写入对象 ,一般会将对象用集合存储起来然后直接将集合写入文件
List<Person> list =new ArrayList<>();
list.add(new Person());
...(可以添加多个)
oos.writeObject(list);
4.关闭流,处理异常
oos.flush();
oos.close();
ObjectInputStream对象的反序列化:
从本地磁盘里用ObjectInputStream将对象文件读入java程序
注1:用集合接收的时候要强转
1.创建对象流对象
ObjectInputStream ois =new ObjectInputStream(
new FileInputStream(new File("文件路径")));
2.读入对象
List<Person> list =new ArrayList<>();
List =(List<Person>)ois.readObject();
3.关闭流,处理异常
ois.close();