在计算机术语中,I/O(input/output)是系统和外部进行交流通信的方式。输入(input)是系统收到的信号或者数据,输出是系统对外发出的信号或者数据。我们通常所说的执行I/O操作就是对于输入或者输出数据的处理。
Java IO是Java提供的一系列用于处理输入和输出数据的API。Java对于输入和输出进行了抽象,用流(Stream)来表示输入输出。流可以代表任何类型的输入源或者输出目标。比如硬盘上的文件,内存,其他设备等。 流由一系列的数据组成,你可以把流想象成水流,程序可以使用输入流来读取数据,使用输出流来写出数据。流支持不同类型的数据,如字节数据,基本类型数据,对象等
从流中读取数据

向流中写入数据

Java Stream中根据处理数据的最小单位不同,可以分为字节流和字符流两种。
-
字节流
数据流中最小的数据单元是字节
-
字符流 数据流中最小的数据单元是字符, Java中的字符是Unicode编码,一个字符占用两个字节。
根据这两种不同的类型,Java提供了一些列的Java类

字节流
字节输入流
InputStream是所有字节输入流的基类,提供了读取字节流的基本方法,其子类通过继承InputStream实现不同形式的字节流。我们先看下InputStream中的关键方法
| 方法 | 方法介绍 |
|---|---|
| public abstract int read() | 从流中读取一个字节数据,抽象方法由子类负责实现真正的读取 |
| public int read(byte b[]) | 从流中读取数组长度的字节数据,内部调用下面的方法实现 |
| public int read(byte b[], int off, int len) | 从流中读取len个字节,写入到从off位置开始的数组中 |
| public long skip(long n) | 跳过流中的几个字节 |
| public int available() | 流中可读字节的数量 |
| public void close() | 关闭字节流,释放系统资源 |
| public synchronized void mark(int readlimit) | 标记当前位置,调用reset方法之后还可以从当前位置开始读取,调用前需要通过markSupported检查实现类四是否支持mark |
| public synchronized void reset() | 重置读取位置为上次 mark 标记的位置 |
| public boolean markSupported() | 判断当前流是否支持标记流 |
ByteArrayInputStream
ByteArrayInputStream把一个数组包装成输入流,从字节数组读取数据。相比于直接使用原始数组,ByteArrayInputStream提供了read-only功能。因为流没有提供更改数组内容的方法。
FileInputStream
FileInputStream从文件系统中读取字节数据,是我们使用比较多的一个类,内部实际读取文件内容的方法为native方法实现,一般读取配置包装类BufferedInputStream使用,减少I/O消耗。
PipedInputStream
PipedInputStream主要用户线程间通信,PipedInputStream连接到PipedOutputStream,一个线程通过PipedOutputStream写数据,另外一个通过PipedInputStream读取数据。但是线程间通信也可以采取共享内存到方式。所以使用过程中应用场景不多。
FilterInputStream
我们都知道Java IO包使用了经典的装饰模式,通过装饰器增加原始输入输出流的功能。FilterInputStream是输入装饰器的基类,本身没有提供特殊的功能,只是简单的把调用转发到原始输入流中。具体装饰器通过实现类来扩展。
-
BufferedInputStream
BufferedInputStream是我们使用比较多的类,提供了读取输入的缓存功能,通过一次读取和缓存多个字节的数据到内存中,减少系统调用带来的开销。但是要注意的是并不是任何情况下通过BufferedInputStream都能提高读取的性能,通过阅读源码可以发现,BufferedInputStream默认读取8K(8192)的缓存数据,如果你一次读取的字节超过了缓存大小的数据,反而增加了一次数据的内存拷贝,降低了程序的性能。所以需要根据自身程序特点决定是否使用。
-
PushbackInputStream
回退流,我们的输入流在只能顺序的从前往后读取字节,PushbackInputStream提供了回退功能,把读取进来不需要的字节回退到输入流的缓存中。
-
DataInputStream
DataInputStream提供了我们从输入流中读取Java基本数据类型数据的功能。根据数据类型字节长度不同,读取相应的字节,转换为我们需要的基本数据类型。比如int类型,读取流中的四个字节,通过移位的方式组合成我们需要的int类型数据。
ObjectInputStream
ObjectInputStream用于对象的反序列化,从流中读取数据,转换为我们需要的Java对象。对象反序列化的过程不包括transient和静态字段。可反序列化的对象必须实现Serializable接口。
字节输出流
OutputStream是所有字节输出流的基类,提供了写出数据的基本方法,其子类通过继承OutputStream实现不同形式的字节输出流。我们先看下OutputStream中的关键方法
| 方法 | 方法介绍 |
|---|---|
| public abstract void write(int b) | 向输出流中写入一个字节,取的是int的低八位字节 |
| public void write(byte b[]) | 向输出流中写入字节数组 |
| public void write(byte b[], int off, int len | 向输出流中写入len长度的字节数据,从b[]的off位置开始 |
| public void flush() | 强制刷新,将缓冲中的数据写入的输出流。这里只是保证写入到输出流,,比如文件,只是保证写入到操作系统缓存。 |
| public void close() | 关闭字节流,释放系统资源 |
ByteArrayOutputStream
ByteArrayOutputStream写入到内存中的字节数组缓存中,数组大小会随着写入数量的增加而自动增长。可以通过toByteArray或者toString获取写入的数据
FileOutputStream
FileOutputStream写入字节到文件中
PipedOutputStream
PipedOutputStream管道输出流需要和PipedOutputStream配合使用,用于线程间通信。
FilterOutputStream
FilterOutputStream和FilterInputStream类似,是输出字节流的装饰类的基类,本身没有提供特殊的功能,只是简单的把调用转发到原始输入流中。具体装饰器通过实现类来扩展。
- BufferedOutputStream BufferedOutputStream也和BufferedInputStream类似,提供了输出字节流的缓冲,通过暂时缓存写入数据,在写入到数据达到一定的数量后,一起写入到外部存储,减少系统调用带来的开销。 BufferedOutputStream默认缓冲区同样是8K(8192)大小。
- DataOutputStream DataOutputStream提供了我们把Java基本数据类型数据写入到输出字节流的功能。
ObjectOutputStream
ObjectOutputStream用于对象的序列化,把Java对象对象写入到输出流中。对象序列化的过程不包括transient和静态字段。可序列化的对象必须实现Serializable接口。
字符流
字符流和字节流类似,基本的类结构和方法和字节流也基本相同。不同过的是字符流读取的单位是字符,而字节流是单个字节。需要注意的是FileReader和FileWriter,不是直接继承的Reader和Writer抽象类,而是通过OutputStreamReader和OutputStreamWriter进行桥接,底层依然使用的FileInputStream和FileOutputStream。
原文地址: blog.devlab.cn/java-io/#mo…
