Java IO

1 IO Stream

Java 类库中,关于 IO 的代码在 java.io package 下,整个包的围绕着:

三个核心接口展开。

需要注意的是:网络传输和磁盘存储都是基于字节的,而语言是基于字符的,二者之间的转换即为编解码。

1.1 InputStream/OutputStream

其中输入指从数据源(磁盘、网络)读取到内存中,输出即为内存数据输出到磁盘或网络等目标地。

I) InputSteam 体系

InputStream 核心方法有:

InputStream 类体系

其中:

II) OutputStream 体系

1.2 Reader/Writer

基于字符读写类是围绕着 Reader 和 Writer 这两个核心接口展开的,磁盘存储和网络传输都是基于字节,由原生字节转换为字符需要进行解码。同样,由字符转换成字节需要做编码。

编解码的核心类是 StreamEncoderStreamDecoder,二者使用 CharsetOutputStreamInputStream 做编解码。其中 Charset 即为 Java 中字符集的抽象,其实现类包含熟知的 ASCII/UTF-8 等。

I) Reader 体系

Reader 核心接口和 InputStream 基本一致,包含 read/close/skip 等,需要注意的是,如 int read() 接口,返回值范围 0-65535,即 4 个字节长度,同样,当流结束时,返回 -1。

II) Writer 体系

1.3 File

在系统设计中,文件通常用来:

java.io.File 是 Java 对文件的抽象类,可用来创建、删除文件,或者判读文件是否真实存在等操作。真正的文件读写依赖的是 FileDescriptor 类,FileDescritor 才是真正操作系统中文件指针(文件描述符)。一个系统能够打开的文件描述符是有限制的,所以当描述符不在使用时,需要调用 close 关闭。

2. 总结

Java 中,将 IO 数据抽象为 Stream - 流,流可以是字节流,也可以是字符流。

因为流操作通常持有系统资源,如 FileInputSteam 是持有文件描述符的,而操作系统可分配的文件描述符是有限的,所以,当流对象使用完毕时,需要关闭流。在流的各个扩展中,都有关闭方法 close 的默认实现。

在 Java7 中,为了解决代码中同时存在多个流的关闭导致的代码无序切庞大问题(通常是在 finnaly 中关闭流),引入了类似 python with 语法的 try-with-resource 语法糖,只需在 try 中包含资源变量,编译器会在代码构建时自动生成 try finally 逻辑,实现流的关闭。而这依赖于流实现了 AutoClosable 接口,当然如果希望在自定义类也能使用 try-with-resource,也可以扩展 AutoClosable 达到这个目的。

在字节流操作和字符流操作类中,都提供了 Buffered** 类,用来提供更高效的读写操作(和 CPU 速度相比,IO 操作是十分缓慢的)。在代码编写中,buffer 思想通常用来解决生产者和消费者速度不匹配可能产生的阻塞问题以及资源有限可能导致的资源争抢问题。

关于 IO 操作的常用类库有 commons-io, guava-io等,对于如计算 校验和、copy 操作,read 操作等都有封装。

参考: