Java IO 流详解
1 .Java IO概念
Java IO:即 Java 输入 / 输出系统。
Java 的 IO 模型设计非常优秀,它使用 Decorator (装饰者)模式,按功能划分 Stream ,您可以动态装配
这些 Stream ,以便获得您需要的功能。
Stream :JAVA 中将数据的输入输出抽象为流,流是一组有顺序的、单向的,有起点和终点的数据集
合。按照流中的最小数据单元又分为字节流和字符流。
IO 流用来处理设备之间的数据传输,Java 程序中,对于数据的输入/输出操作 都是以“流”的方式进行的。
java.io 包下提供了各种“流”类的接口,用以获取不同种类的数据,并通过标准的方法输入或输出数
据。
对于计算机来说,数据是以二进制形式读出或写入。我们可以把文件想象为一个桶,我们通过管道将桶
里的水抽出来。这里的管道也就相当于Java中的流。流的本质是一种有序的数据集合,有数据源和目的
地。
2 .Java IO流分类
2.1. 按照流的方向(输出输入都是站在程序所在内存的角度为依据划分的)
-
输入流:只能从内存中读数据
-
输出流:只能向文件中写数据
-
输入:读取外部数据(磁盘、光盘等存储设备的数据)到程序(内存)中。
-
输出:将程序(内存)数据输出到磁盘、光盘等存储设备中
- -
InputStream :字节输入流
-
OutputStream :字节输出流
-
Reader :字符输入流
-
Writer :字符输出流
-
在日常工作中,字节流一般用来处理图像,视频,以及PPT,Word类型的文件。字符流一般
用于处理纯文本类型的文件,如TXT文件等,字节流可以用来处理纯文本文件,但是字符流不
能用于处理图像视频等非文本类型的文件。
2.2. 按处理数据单位(字节流与字符流)
1字符 = 2字节 、 1字节(byte) = 8位(bit) 、 一个汉字占两个字节长度
字节流:每次读取(写出)一个字节,当传输的资源文件有中文时,就会出现乱码。
字符流:每次读取(写出)两个字节,有中文时,使用该流就可以正确传输显示中文。
2.3. 按功能不同分为(节点流与处理流)
节点流:
以从或向一个特定的地方(节点)读写数据。
文件流:
FileInputStream,FileOutputStrean,FileReader,FileWriter,它们都会直接
操作文件,直接与 OS 底层交互。因此他们被称为节点流 ,注意:使用这几个流的对象
之后,需要关闭流对象,因为 java 垃圾回收器不会主动回收。不过在 Java7 之后,可以
在 try() 括号中打开流,最后程序会自动关闭流对象,不再需要显示地 close。
数组流:
ByteArrayInputStream,ByteArrayOutputStream,CharArrayReader,
CharArrayWriter,对数组进行处理的节点流。
字符串流:
StringReader,StringWriter,其中 StringReader 能从 String 中读取数据并
保存到 char 数组。
管道流:
PipedInputStream,PipedOutputStream,PipedReader,PipedWrite,对管
道进行处理的节点流。
处理流:
是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。
缓冲流 :
BufferedImputStrean,BufferedOutputStream,BufferedReader ,
BufferedWriter,需要父类作为参数构造,增加缓冲功能,避免频繁读写硬盘,可以初
始化缓冲数据的大小,由于带了缓冲功能,所以就写数据的时候需要使用 flush 方法,另
外,BufferedReader 提供一个 readLine( ) 方法可以读取一行,而 FileInputStream 和
FileReader 只能读取一个字节或者一个字符,因此 BufferedReader 也被称为行读取
器。
转换流:
InputStreamReader,OutputStreamWriter,要 inputStream 或
OutputStream 作为参数,实现从字节流到字符流的转换,我们经常在读取键盘输入
(System.in)或网络通信的时候,需要使用这两个类。
数据流:DataInputStream,DataOutputStream,提供将基础数据类型写入到文件中,
或者读取出来。
以BufferedReader为例。处理流的构造方法总要带上一个其他的流对象做参数。一个流
对象会经过其他流的多次包装。
3 Java IO流特性
- 顺序存取:可以一个接一个地往流中写入一串字节,读出时也将按写入顺序读取一串字节,不能随机
访问中间的数据。(RandomAccessFile可以从文件的任意位置进行存取(输入输出)操作) - 先进先出:最先写入输出流的数据最先被输入流读取到。
- 只读或只写:每个流只能是输入流或输出流的一种,不能同时具备两个功能,输入流只能进行读操
作,对输出流只能进行写操作。在一个数据传输通道中,如果既要写入数据,又要读取数据,则要
分别提供两个流。
4 Java IO流接口
1. File(文件特征与管理):File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的
思想来操作文件和文件夹。 File类保存文件或目录的各种元数据信息,包括文件名、文件长度、最
后修改时间、是否可读、获取当前文件的路径名,判断指定文件是否存在、获得当前目录中的文件
列表,创建、删除文件和目录等方法。
2. InputStream(二进制):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入
流都具有的共同特征。
3. OutputStream(二进制):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输
出流都具有的共同特征。
4. Reader(文件格式):抽象类,基于字符的输入操作。
5. Writer(文件格式):抽象类,基于字符的输出操作。
6. RandomAccessFile(随机文件):一个独立的类,直接继承至Object.它的功能丰富,可以从文件
的任意位置进行存取(输入输出)操作。
一个接口指的是Serializable.掌握了这些IO的核心操作那么对于Java中的IO体系也就有了一个初步的认识
了。
5 Java IO流对象
5.1 输入字节流InputStream
- ByteArrayInputStream:字节数组输入流,该类的功能就是从字节数组(byte[])中进行以字节为单
位的读取,也就是将资源文件都以字节的形式存入到该类中的字节数组中。 - PipedInputStream:管道字节输入流,它和PipedOutputStream一起使用,能实现多线程间的管
道通信。 - FilterInputStream :装饰者模式中处于装饰者,具体的装饰者都要继承它,所以在该类的子类下都
是用来装饰别的流的,也就是处理类。具体装饰者模式在下面会讲解到,到时就明白了。 - BufferedInputStream:缓冲流,对处理流进行装饰,增强,内部会有一个缓存区,用来存放字
节,每次都是将缓存区存满然后发送,而不是一个字节或两个字节这样发送。效率更高。 - DataInputStream:数据输入流,它是用来装饰其它输入流,它“允许应用程序以与机器无关方式从
底层输入流中读取基本 Java 数据类型”。 - FileInputSream:文件输入流。它通常用于对文件进行读取操作。
- File:对指定目录的文件进行操作,具体可以查看讲解File的博文。注意,该类虽然是在IO包下,但
是并不继承自四大基础类。 - ObjectInputStream:对象输入流,用来提供对“基本数据或对象”的持久存储。在反序列化中使
用。
5.2 输出字节流OutputStream
- OutputStream 是所有的输出字节流的父类,它是一个抽象类。
- ByteArrayOutputStream、FileOutputStream 是两种基本的介质流,它们分别向Byte 数组、和本
地文件中写入数据。PipedOutputStream 是向与其它线程共用的管道中写入数据。 - ObjectOutputStream 和所有FilterOutputStream 的子类都是装饰流,同样在序列化中使用。
8.5.3 字符输入流 Reader - Reader :所有的输入字符流的父类,它是一个抽象类。
- CharReader 、 StringReader :两种基本的介质流,它们分别将Char 数组、String中读取数据。
PipedReader 是从与其它线程共用的管道中读取数据。 - BufferedReader :一个装饰器,它和其子类负责装饰其它Reader 对象。
- FilterReader :所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装
饰,会增加一个行号。 - InputStreamReader :一个连接字节流和字符流的桥梁,它将字节流转变为字符流。 FileReader
可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为
Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和
InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。
5.4 字符输出流Writer
- Writer:所有的输出字符流的父类,它是一个抽象类。
- CharArrayWriter、StringWriter:两种基本的介质流,它们分别向Char 数组、String 中写入数
据。PipedWriter 是向与其它线程共用的管道中写入数据, - BufferedWriter:一个装饰器为Writer 提供缓冲功能。
- PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
- OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是这么
一个实现此功能的类。功能和使用和OutputStream类似。
6 Java IO流方法
6.1 字节流方法
字节输入流InputStream主要方法:
read() :从此输入流中读取一个数据字节。
read(byte[] b) :从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。
read(byte[] b, int off, int len) :从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。
close():关闭此输入流并释放与该流关联的所有系统资源。
字节输出流OutputStream主要方法:
write(byte[] b) :将 b.length 个字节从指定 byte 数组写入此文件输出流中。
write(byte[] b, int off, int len) :将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。
write(int b) :将指定字节写入此文件输出流。
close() :关闭此输入流并释放与该流关联的所有系统资源。
6.2 字符流方法
字符输入流Reader主要方法:
read():读取单个字符。
read(char[] cbuf) :将字符读入数组。
read(char[] cbuf, int off, int len) : 将字符读入数组的某一部分。
read(CharBuffer target) :试图将字符读入指定的字符缓冲区。
flush() :刷新该流的缓冲。
close() :关闭此流,但要先刷新它。
字符输出流Writer主要方法:
write(char[] cbuf) :写入字符数组。
write(char[] cbuf, int off, int len) :写入字符数组的某一部分。
write(int c) :写入单个字符。
write(String str) :写入字符串。
write(String str, int off, int len) :写入字符串的某一部分。
flush() :刷新该流的缓冲。
close() :关闭此流,但要先刷新它。
BufferedWriter类newLine() :写入一个行分隔符。这个方法会自动适配所在系统的行分隔符。
BufferedReader类readLine() :读取一个文本行。
7 字节流与字符流的转换
字节流与字符流的转换主要用于文本文件在硬盘中以字节流的形式存储时,通过InputStreamReader读
取后转化为字符流给程序处理,程序处理的字符流通过OutputStreamWriter转换为字节流保存。
转换流有哪些基本特点呢?
- 是字符流和字节流之间的桥梁
- 可对读取到的字节数据经过指定编码转换成字符
- 可对读取到的字符数据经过指定编码转换成字节
那么什么时候使用转换流呢? - 当字节和字符之间有转换动作
- 流操作的数据需要编码或解码
具体的对象体现在哪些方面? - InputStreamReader :字节到字符的桥梁
- OutputStreamWriter :字符到字节的桥梁
这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字
节流对象进来。 - OutputStreamWriter(OutStreamout) :将字节流以字符流输出。
- InputStreamReader(InputStream in) :将字节流以字符流输入
10.
8 字节流与字符流的区别
- 读写的单位有所不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,
一次可能读多个字节。 - 处理的对象有所不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类
型的数据。 - 字节流没有缓冲区,是直接输出的,而字符流是输出到缓冲区的。因此在输出时,字节流不调用
colse()方法时,信息已经输出了,而字符流只有在调用close()方法关闭缓冲区时,信息才输出。要
想字符流在未关闭时输出信息,则需要手动调用flush()方法。