第十七章 二进制 I/O
17.1 在 Java 中如何处理文本I/O
使用 Scanner 类读取文本数据 ,使用 PrintWriter 类写文本數据 。
17.2 文本 I/O 与二进制 I/O
由于二进制 I / O 不需要编码和解码 ,所以 , 它比文本 I / O 效率高 。 二进制文件与主机的
编码方案无关,因此 , 它是可移植的 。 在任何机器上的 Java 程序可以读取 Java 程序所创建
的二进制文件 。 这就是为什么 Java 的类文件存储为二进制文件的原因 。 Java 类文件可以在
任何具有 Java 虚拟机的机器上运行 。
17.3 二进制 I/O 类
抽象类 InputStream 是读取二进制数据的根类 ,抽象类 OutputStream 是写入二进制数据的根类 。
17.3.1 FilelnputStream 和 FiileOutputStream
FilelnputStream 类和 FiileOutputStream 类用于从 / 向文件读取 / 写人字节 。
当流不再需要使用时 ,记得使用 close() 方法将其关闭 , 或者使用 try with resource语句自动关闭 。 不关闭流可能会在输出文件中造成數据受损 , 或导致其他的程序设计错误 。
17.3.2 FilterInputStream 和 FileterOutStream
过滤器数据流 ( filter stream ) 是为某种目的过滤字节的数据流 。 基本字节输人流提供的
读取方法 read 只能用来读取字节 。 如果要读取整数值 、 双精度值或字符串 , 那就需要一个
过滤器类来包装字节输入流 。 使用过滤器类就可以读取整数值 、 双精度值和字符串 , 而不是
字节或字符 。 FilterlnputStream 类和 FilterOutputStream 类是过滤数据的基类 。 需要处理
基本数值类型时,就使用 DatalnputStream 类和 DataOutputStream 类来过滤字节 。
17.3.3 DataInputStream 和 DateOutStream
DatalnputStream 从数据流读取字节 , 并且将它们转换为合适的基本类型值或字符串。DataOutputStream 将基本类型的值或字符串转换为字节 , 并且将字节输出到数据流。
基本类型的值不需要做任何转化就可以从内存复制到输出数据流 。
1.二进制 I / O 中的宇符与宇符串
UTF 8 字符起始的几位表明这个字符是存储在一个宇节 、 两个字节还是三个字节中 。 如果首位是 0 , 那它就是一个字节的字符 。 如果前三位是 110 , 那它就是两字节序列的第一个宇节 。 如果前四位是 1110, 那它就是三字节序列的第一个字节 。 UTF 8 字符之前的两个字节用来存储表明字符串中的字符个数的信息 。
2 . 创建 DatalnputStream 类和 DataOutputStream 类
17.3.4 BufferedInputStream 和 BufferedOutputStream
使用 BufferInputStream 时 , 磁盘上的整块数据一次性地读入到内存中的缓冲区中 。 然后从缓冲区中将个别的数据传递到程序中 。
使用BufferedOutputStream , 个别的数据首先写人到内存中的缓冲区中 。 当缓冲区已满时 , 缓冲区中的所有数据一次性写入到磁盘中。
17.4 对象 I/O
Ob j ectlnputSt ream 类和 ObjectOutputStream 类除了可以实现基本数据类型与
字符串的输人和输出之外 , 还可以实现对象的输人和输出 。
17.5 Serializable 接口
可以写人输出流中的对象称为可序列化的( serializable )。因为可序列化的对象是 ; java . io . Serializable 接口的实例,所以, 可序列化对象的类必须实现 Serializable 接口 。
当存储一个可序列化对象时,会对该对象的类进行编码 。 编码包括类名 、 类的签名 、 对象实例变量的值以及该对象引用的任何其他对象的闭包 ,但是不存储对象静态变量的值 。
注意 : 非序列化的数据域
如果一个对象是 Serializable 的实例 , 但它包含了非序列化的实例数据域,那么可以序列化这个对象吗 ? 答案是否定的 。 为了使该对象是可序列化的 ,需要给这些数据域加上关键字 transient , 告诉 Java 虚拟机将对象写入对象流时忽略这些数据域 。
注意: 重复的对象
如果一个对象不止一次写入对象流 , 会存储对象的多份副本吗 ? 答案是不会 。第一次写入
一个对象时,就会为它创建一个序列号 。 Java 虚拟机将对象的所有内容和序列号一起写入
对象流 。 以后每次存储时 ,如果再写入相同的对象 ,就只存储序列号 。 读出这些对象时 ,
它们的引用相同 ,因为在内存中实际上存储的只是一个对象 。
17.6 序列化数组
如果数组中的所有元素都是可序列化的,这个数组就是可序列化的 。 一个完整的数组可
以用 writeObject 方法存入文件, 随后用 readObject 方法恢复 。
17.7 随机访问文件
Java 提供了RandomAccessFile 类 ,允许从文件的任何位置进行數据的读写 。
流都是只读的 ( read . only ) 或只写的 ( write . only ) 。 这些流称为顺序( sequential) 流 。 使用顺序流打开的文件称为顺序访问文件 。 顺序访问文件的内容不能更新 。 然而 , 经常需要修改文件 。 Java 提供了 RandomAccessFile 类,允许在文件的任意位置上进行读写 。 使用 RandomAccessFile 类打开的文件称为随机访问文件 。