JDK源码rt.jar中java.io包拆解

朝花夕拾

基于 jdk8 https://docs.oracle.com/javase/8/docs/api/index.html

概览

java.io包UML图class

java.io 包中有输入输出流 InputStream/OutputStream ,字符输入输出 Reader/Writer ,全部实现了 Closeable.close() 方法。Closeable 接口又继承自用来实现Java try-with-resource 的 AutoCloseable 接口。还有从二进制流中的字节读取、写入java基本数据类型的 DataInput/DataOutput ,以及继承了 DataInput/DataOutput 用于读取写入Java对象、数组、字符串的接口 ObjectInput/ObjectOutput 。还有文件类 File ,随机读写文件类 RabdomAccessFile 。异常类 IOException/IOError。

接口

java.io包UML图interface

java.io 包下所有IO流和字符流都实现了 AutoCloseable 接口,但是注意 AutoCloseable 接口位于 java.lang 包下。对于IO流和字符流这种在关闭之前可以保存资源(例如文件或套接字句柄)的对象。当退出在资源规范头中已声明该对象的 try-with-resources 块时,将自动调用 AutoCloseable.close() 方法。这种构造可确保及时释放,避免资源耗尽异常和可能发生的错误。虽然 AutoCloseable.close() 方法声明中返回的是 Exception 异常,但是 javadoc 中要求实现者准确的异常类,或者不抛出异常。close 操作存在失败的可能,而 close() 方法正常只会被调用一次,所以实现者应该在抛出异常之前释放持有的资源,并在实现内部标记资源为已关闭,这样做可以确保资源被及时释放。实现者也不要在 close() 方法中抛出 InterruptedException 异常, 这个异常会与线程的中断状态相互作用引发运行时行为的异常。并且如果 close() 方法中出现了 InterruptedException 异常,实现者不应该继续向外抛出。AutoCloseable.close() 与 Closeable.close() 方法不同,前者不是幂等的,多次调用会有副作用,而后者是幂等的,大于一次的调用无效。所以建议 AutoCloseable.close() 的实现者在实现 close() 方法时实现幂等。

Closeable 接口表示可以关闭目标资源的数据,在调用 close() 方法时放弃持有的资源。如果流已经关闭,则调用 Closeable.close() 无效。在抛出IOException之前,应该放弃基础资源,并在内部将Closeable标记为已关闭。

Flushable 是可刷新数据的目标。调用 flush() 方法将输出到缓冲区中的数据写入底层流。

DataInput/DataOutput 用于从二进制流中读取Java原始数据类型和写入,转换 String 为修改后的 UTF-8 格式字节流和读取。如果在读取所需的字节数之前已到达文件末尾,则将引发 EOFException(这是IOException 的一种)。如果除了文件末尾以外的任何其他原因都无法读取任何字节比如输入流已关闭,则抛出 EOFException 以外的 IOException 。如果无法写出数据,则也会抛出 IOException。

ObjectInput/ObjectOutput 继承了 DataInput/DataOutput 接口以扩展对象、数组和字符串的读写。

InputStream/OutputStream 两个抽象类,是所有字节输出输入流的超类。需要定义InputStream子类的应用程序必须始终提供一种返回输入的下一个字节的方法。需要定义OutputStream子类的应用程序必须始终至少提供一种写入一个字节输出的方法。

Reader/Writer 读取字符流的抽象类。子类必须实现的唯一方法是读取 read(char [],int,int),写入 write(char[], int, int),输出 flush(),关闭流 close() 。但是,大多数子类将覆盖此处定义的某些方法,以提供更高的效率或附加功能。

FileReader 用于读取字符文件。此类的构造函数假定默认字符编码和默认字节缓冲区大小是适当的。要自己指定这些值,请在 FileInputStream 上构造一个 InputStreamReader。 FileReader 用于读取字符流。为了读取原始字节流,请考虑使用 FileInputStream。

FileWriter 同上,要自己指定一些值,请在 FileOutputStream 上构造一个 OutputStreamWriter。 文件是否可用或是否可以创建取决于底层平台。特别是某些平台,一次只允许一个 FileWriter(或其他文件写入对象)打开一个文件进行写入。在这种情况下,如果所涉及的文件已经打开,则此类中的构造函数将失败。 FileWriter 用于编写字符流。要写入原始字节流,请考虑使用FileOutputStream。

InputStream/Reader

java.io包UML图input

ObjectStreamConstants 写入对象序列化流的常量。

DataInputStream 数据输入流允许应用程序以与机器无关的方式从基础输入流中读取原始Java数据类型。DataInputStream 对于多线程访问不一定是安全的,由用户实现。

ObjectInputStream 只能从流中读取支持 java.io.Serializable 或 java.io.Externalizable 接口的对象。可以使用 DataInput 上的适当方法从流中读取原始数据类型。反序列化过程将忽略声明为瞬态或静态的字段。对其他对象的引用会导致根据需要从流中读取这些对象。使用引用共享机制可以正确还原对象图。反序列化时始终分配新对象,以防止现有对象被覆盖。读取对象类似于运行新对象的构造函数。为该对象分配了内存,并将其初始化为零(NULL)。为不可序列化的类调用无参数构造函数,然后从流中恢复可序列化类的字段,该流从最接近 java.lang.Object 的可序列化类开始,并以该对象的最特定类结束。在序列化和反序列化过程中需要特殊处理的可序列化类应实现 writeObject(java.io.ObjectOutputStream stream) readObject(java.io.ObjectInputStream stream readObjectNoData() 。序列化不会读取任何值或将值分配给未实现 java.io.Serializable 接口的任何对象。不可序列化的对象的子类可以被序列化。在这种情况下,不可序列化的类必须具有no-arg构造函数,以允许对其字段进行初始化。在这种情况下,子类负责保存和恢复不可序列化类的状态。通常,该类的字段是可访问的(公共,程序包或受保护),或者存在可用于还原状态的get和set方法。枚举常量的反序列化方式不同于普通的可序列化或可外部化的对象。枚举常量的序列化形式仅由其名称组成;常量的字段值不发送。为了反序列化枚举常量,ObjectInputStream 从流中读取常量名称。然后,通过以枚举常量的基本类型和接收到的常量名称作为参数的静态方法 Enum.valueOf(Class,String)来获取反序列化的常量。像其他可序列化或可外部化的对象一样,枚举常量可以用作随后出现在序列化流中的反向引用的目标。无法自定义反序列化枚举常量的过程:反序列化期间,将忽略由枚举类型定义的任何特定于类的readObject,readObjectNoData和readResolve方法。同样,任何serialPersistentFields或serialVersionUID字段声明也将被忽略-所有枚举类型的固定serialVersionUID为0L。

ObjectOutputStream 大致同上。

PipedInputStream 管道输入流应连接到管道输出流。然后,管道输入流将提供写入管道输出流的任何数据字节。通常,一个线程从 PipedInputStream 对象读取数据,而另一线程将数据写入相应的PipedOutputStream。不建议尝试从单个线程使用两个对象,因为这可能使线程死锁。管道输入流包含一个缓冲区,在限制范围内将读取操作与写入操作分离。如果向连接的管道输出流提供数据字节的线程不再活动,则认为管道已损坏。

SequenceInputStream 表示其他输入流的逻辑串联,构造参数包含多个输入流。读取完第一个输入流,接着读取完第二个输入流,依此类推,直到在最后一个包含的输入流中到达文件末尾。

FileInputStream 从文件系统中的文件获取输入字节。可用的文件取决于主机环境。 FileInputStream 用于读取原始字节流,例如图像数据。要读取字符流,请考虑使用 FileReader。

ByteArrayInputStream 包含一个内部缓冲区,该缓冲区包含可以从流中读取的字节。内部计数器跟踪由read方法提供的下一个字节。 关闭ByteArrayInputStream无效。可以在关闭流之后调用此类中的方法,而不会产生IOException。

FilterInputStream 内部有一个 InputStream 变量,用于装饰其他一些输入流,可能会沿途转换数据或提供其他功能。类FilterInputStream本身只是使用将所有请求传递到所包含的输入流的版本来覆盖InputStream的所有方法。 而其子类可以进一步覆盖其中的某些方法,用以丰富基础流的功能。

BufferedInputStream 是 FilterInputStream 子类,向另一个输入流添加功能,即缓冲输入并支持mark和reset方法的功能。创建BufferedInputStream时,将创建一个内部缓冲区数组。当读取或跳过流中的字节时,根据需要从包含的输入流中重新填充内部缓冲区,一次填充许多字节。标记操作会记住输入流中的一个点,并且重置操作将导致在从包含的输入流中获取新字节之前重新读取自最近标记操作以来的所有字节。

PushbackInputStream 是 FilterInputStream 子类,读取字节后可以将读取过的字节推回到字节流,以便其他操作重新读取这些字节。

Reader 读取字符流的抽象类。子类必须实现的唯一方法是read(char [],int,int)和close()。但是,大多数子类将覆盖此处定义的某些方法,以提供更高的效率和/或附加功能。

StringReader 构造函数参数是 String ,用于从一个字符串中读取字符流。

PipedReader 字符流的读取管道。

InputStreamReader 是从字节流到字符流的桥梁:它读取字节,并使用指定的字符集将其解码为字符。它使用的字符集可以按名称指定,也可以显式指定,也可以接受平台的默认字符集。 InputStreamReader 的 read()方法之一的每次调用都可能导致从基础字节输入流中读取一个或多个字节。为了实现字节到字符的有效转换,与满足当前读取操作所需的字节数相比,可以从基础流中提前读取更多字节。 为了获得最高的效率,请考虑将InputStreamReader包装在BufferedReader中。

FileReader 读取字符文件的便捷类。此类的构造函数假定默认字符编码和默认字节缓冲区大小是适当的。要自己指定这些值,请在 FileInputStream 上构造一个InputStreamReader。FileReader用于读取字符流。为了读取原始字节流,请考虑使用FileInputStream。

FilterReader 读取过滤的字符流的抽象类。抽象类FilterReader本身提供了默认方法,内部装饰Reader类型的变量,该方法将所有请求传递到所包含的流。 FilterReader的子类应覆盖其中的某些方法,并且还可以提供其他方法和字段。

PushbackReader 允许将读取过的字符推回字符流中以便其他方法重新读取。

CharArrayReader 此类实现了可用作字符输入流的字符缓冲区。

BufferedReader 从字符输入流中读取文本,缓冲字符。可以指定缓冲区大小,也可以使用默认大小。对于大多数用途,默认值足够大。 通常,由读取器发出的每个读取请求都会导致对基础字符或字节流进行相应的读取请求。如果不进行缓冲,则每次调用read()或readLine()都可能导致从文件中读取字节,将其转换为字符,然后返回,这可能会非常低效。

LineNumberReader 跟踪行号的缓冲字符输入流。此类定义方法setLineNumber(int)和getLineNumber() 分别用于设置和获取当前行号。 默认情况下,行编号从0开始。在读取数据时,此编号在每个行终止符处递增,并且可以通过调用setLineNumber(int)进行更改。但是请注意,setLineNumber(int)实际上不会更改流中的当前位置;它只会更改getLineNumber()返回的值。

OutputStream/Writer

java.io包UML图output

RandomAccessFile

java.io包UML图randomaccess

RabdomAccessFile 此类的实例支持读取和写入随机访问文件。随机访问文件的行为就像存储在文件系统中的大字节数组一样。隐式数组中有一种游标或索引,称为文件指针;输入操作从文件指针开始读取字节,然后使文件指针越过读取的字节。如果随机访问文件是在读/写模式下创建的,则输出操作也可用;输出操作从文件指针开始写入字节,然后使文件指针前进超过写入的字节。写入超出隐含数组当前末尾的输出操作将导致数组扩展。可以通过getFilePointer 方法读取文件指针,并通过 seek 方法设置文件指针。 通常,对于此类中的所有读取例程,如果在读取所需的字节数之前已到达文件末尾,则会引发 EOFException。如果由于文件末尾以外的任何其他原因而无法读取任何字节比如流已关闭,则抛出其他的 IOException。

概览方法图

java.io包UML图method