流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。Java
的 I/O
是建立在流(Stream
)之上的,输入流读取数据,输出流写入数据。流是同步的 ,也就是说当请求流读一段数据时,阻塞等待 直到有数据。Java
还支持使用通道和缓冲区的非阻塞 I/O
(NIO
),暂不讨论。
流的分类 按流向分类
输入流: 程序可以从中读取 数据的流
输出流: 程序能向其中写入 数据的流
按数据传输单位分类
字节流 以字节(8 位二进制)为单位进行处理。主要用于读写诸如图像或声音的二进制数据。
字符流 字符流中的对象融合了编码表,以字符为单位,根据码表映射字符,一次可能读多个字节,字符流只能处理字符文本类型的数据。字符流是对字节流进行了封装,方便操作,在最底层所有的输入输出都是字节形式的。后缀是 Stream
是字节流,而后缀是 Reader, Writer
是字符流。
按功能分类
节点流 从特定的地方读写的流类,如磁盘或者一块内存区域,直接与数据源相连读入或读出。
处理流 使用节点流作为输入或输出,处理流是使用一个已经存在的输入流或者输出流连接创建的。
流操作的类或接口 基本类和接口
File
:文件类
RandomAccessFile
:随机存取文件类
InputStream
:字节输入流
OutputStream
:字节输出流
Reader
:字符输入流
Writer
:字符输出流
流类的结构图
各个类基本介绍:
文件操作FileInputStream, FileOutputStream, FileReader, FileWriter
管道操作PipedInputStream, PipedOutStream, PipedReader, PipedWriter
,PipedInputStream
的实例必须要和 PipedOutputStream
的实例共同使用,共同完成管道的读取写入操作,主要用于线程操作。
字节/字符数组ByteArrayInputStream, ByteArrayOutputStream, CharArrayReader, CharArrayWriter
,在内存中开辟了一个字节或字符数组。
缓冲流BufferedInputStream, BufferedOutputStream, BufferedReader, BufferedWriter
,是带缓冲区的处理流。缓冲区的作用的主要目的是:避免每次和硬盘打交道,提高数据访问的效率。
转化流InputStreamReader, OutputStreamWriter
,把字节转化成字符。
过滤流FilterInputStream, FileOutputStream
,装饰模式,用来装饰基本流。
数据流DataInputStream, DataOutputStream
,字节流只能单字节的输出,但是 long
类型(8 字节)或 float
类型(4 字节)是多字节的,需要逐字节或者转换为字符串输出,数据流提供了这个解决方案。数据流可以用二进制格式读写 Java
的基本数据类型和字符串。
打印流PrintStream, PrintWriter
,一般是打印到控制台。
对象流ObjectInputStream, ObjectOutputStream
,把封装的对象直接输出,而不是一个个在转换成字符串再输出。
序列化流SequenceInputStream
,把对象序列化,直接转换成二进制,写入介质中。
流分类表格
Java IO
是采用的是装饰模式,即采用处理流来包装节点流的方式,来达到代码通用性
处理流和节点流的区分方法,节点流在新建时需要一个数据源(文件、网络)作为参数,而处理流需要一个节点流作为参数
处理流的作用就是提高代码通用性,编写代码的便捷性,提高性能
节点流都是对应抽象基类的实现类,它们都实现了抽象基类的基础读写方法
常见输入输出流 Java
提供的基本输入输出流中,字节流类为 java.io.InputStream/OutputStream
,字符流类为 java.io.Reader/Writer
,它们都是抽象类,提供了读写数据需要的基本方法。
字节流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public abstract class InputStream implements Closeable { public abstract int read () throws IOException ; public int read (byte b[]) throws IOException {...} public int read (byte b[], int off, int len) throws IOException {...} public long skip (long n) throws IOException {...} public int available () throws IOException ; public void close () throws IOException ; public abstract class OutputStream implements Closeable , Flushable { public abstract void write (int b) throws IOException ; public void write (byte b[]) throws IOException {...} public void write (byte b[], int off, int len) throws IOException {...} public void flush () throws IOException ; public void close () throws IOException ; }
字符流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public abstract class Reader implements Readable , Closeable { public int read (java.nio.CharBuffer target) throws IOException {...} public int read () throws IOException {...} public int read (char cbuf[]) throws IOException {...} abstract public int read (char cbuf[], int off, int len) throws IOException ; public long skip (long n) throws IOException {...} public boolean ready () throws IOException {...} abstract public void close () throws IOException ; ... } public abstract class Writer implements Appendable , Closeable , Flushable { public void write (int c) throws IOException {...} public void write (char cbuf[]) throws IOException {...} abstract public void write (char cbuf[], int off, int len) throws IOException ; public void write (String str) throws IOException {...} public void write (String str, int off, int len) throws IOException {...} public Writer append (CharSequence csq) throws IOException { public Writer append (CharSequence csq, int start, int end) throws IOException {...} public Writer append (char c) throws IOException {...} abstract public void flush () throws IOException ; abstract public void close () throws IOException ; ... }
字节字符转换流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class InputStreamReader extends Reader { public InputStreamReader (InputStream in) {...} public InputStreamReader (InputStream in, String charsetName) throws UnsupportedEncodingException {...} public InputStreamReader (InputStream in, Charset cs) {...} public InputStreamReader (InputStream in, CharsetDecoder dec) {...} public String getEncoding () {...} } public class OutputStreamWriter extends Writer { public OutputStreamWriter (OutputStream out, String charsetName) throws UnsupportedEncodingException {...} public OutputStreamWriter (OutputStream out) {...} public OutputStreamWriter (OutputStream out, Charset cs) {...} public OutputStreamWriter (OutputStream out, CharsetEncoder enc) {...} public String getEncoding () {...} }
字节字符转换,需要在构造方法中指定编解码类型,如果不指定使用平台默认。
InputStreamReader
可对读取到的字节数据经过指定编码转换成字符。
OutputStreamWriter
可对读取到的字符数据经过指定编码转换成字节。
过滤流 过滤流是装饰模式中的装饰者,基本输入输出流是被装饰者,过滤流用来装饰其他基本流。过滤器流以链的形式进行连接,通过构造方法把流绑定,这种连接是永久的,过滤器无法无法与流断开连接。链中除了最后一个过滤器外,不能从中间流读取数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public class FilterInputStream extends InputStream { protected volatile InputStream in; public int read () throws IOException { return in.read(); } ... } public class FilterOutputStream extends OutputStream { protected OutputStream out; public void write (int b) throws IOException { out.write(b); } ... }
缓冲流 不带缓冲的操作,每读一个字节就要写入一个字节。由于涉及磁盘的 IO
操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多! 缓冲流将写入的数据存储在缓冲区中,直到缓冲区满或者刷新输出流 ,然后将数据一次全部写入低层输出流。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class BufferedInputStream extends FilterInputStream { public BufferedInputStream (InputStream in) {...} public BufferedInputStream (InputStream in, int size) {...} ... } public class BufferedOutputStream extends FilterOutputStream { public BufferedOutputStream (OutputStream out) {...} public BufferedOutputStream (OutputStream out, int size) {...} ... } public class BufferedReader extends Reader { public BufferedReader (Reader in) {...} public BufferedReader (Reader in, int sz) {...} } public class BufferedWriter extends Writer { public BufferedWriter (Writer out) {...} public BufferedWriter (Writer out, int sz) {...} }
参数解析:
InputStream/OutputStream/Reader/Writer
底层字节/字符流,可以从中读取或写入未缓冲的数据。字符缓冲流中的参数,通常会使用字节字符转换流作为参数 InputStreamReader/OutputStreamWriter
。
size
缓冲区的大小,默认为 8192 个字节。
参考文档
Java
源码
Java IO流学习总结
Java IO流分析整理