ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
### 存储和恢复数据 `PrintWriter` 是用来对可读的数据进行格式化。但如果要输出可供另一个“流”恢复的数据,我们可以用 `DataOutputStream` 写入数据,然后用 `DataInputStream` 恢复数据。当然,这些流可能是任何形式,在下面的示例中使用的是一个文件,并且对读写都进行了缓冲。注意 `DataOutputStream` 和 `DataInputStream` 是面向字节的,因此要使用 `InputStream` 和 `OutputStream` 体系的类。 ```java // iostreams/StoringAndRecoveringData.java import java.io.*; public class StoringAndRecoveringData { public static void main(String[] args) { try ( DataOutputStream out = new DataOutputStream( new BufferedOutputStream( new FileOutputStream("Data.txt"))) ) { out.writeDouble(3.14159); out.writeUTF("That was pi"); out.writeDouble(1.41413); out.writeUTF("Square root of 2"); } catch (IOException e) { throw new RuntimeException(e); } try ( DataInputStream in = new DataInputStream( new BufferedInputStream( new FileInputStream("Data.txt"))) ) { System.out.println(in.readDouble()); // Only readUTF() will recover the // Java-UTF String properly: System.out.println(in.readUTF()); System.out.println(in.readDouble()); System.out.println(in.readUTF()); } catch (IOException e) { throw new RuntimeException(e); } } } ``` 输出结果: ``` 3.14159 That was pi 1.41413 Square root of 2 ``` 如果我们使用 `DataOutputStream` 进行数据写入,那么 Java 就保证了即便读和写数据的平台多么不同,我们仍可以使用 `DataInputStream` 准确地读取数据。这一点很有价值,众所周知,人们曾把大量精力耗费在数据的平台相关性问题上。但现在,只要两个平台上都有 Java,就不会存在这样的问题[^3]。 当我们使用 `DastaOutputStream` 时,写字符串并且让 `DataInputStream` 能够恢复它的唯一可靠方式就是使用 UTF-8 编码,在这个示例中是用 `writeUTF()` 和 `readUTF()` 来实现的。UTF-8 是一种多字节格式,其编码长度根据实际使用的字符集会有所变化。如果我们使用的只是 ASCII 或者几乎都是 ASCII 字符(只占 7 比特),那么就显得及其浪费空间和带宽,所以 UTF-8 将 ASCII 字符编码成一个字节的形式,而非 ASCII 字符则编码成两到三个字节的形式。另外,字符串的长度保存在 UTF-8 字符串的前两个字节中。但是,`writeUTF()` 和 `readUTF()` 使用的是一种适用于 Java 的 UTF-8 变体(JDK 文档中有这些方法的详尽描述),因此如果我们用一个非 Java 程序读取用 `writeUTF()` 所写的字符串时,必须编写一些特殊的代码才能正确读取。 有了 `writeUTF()` 和 `readUTF()`,我们就可以在 `DataOutputStream` 中把字符串和其它数据类型混合使用。因为字符串完全可以作为 Unicode 格式存储,并且可以很容易地使用 `DataInputStream` 来恢复它。 `writeDouble()` 将 `double` 类型的数字存储在流中,并用相应的 `readDouble()` 恢复它(对于其它的书类型,也有类似的方法用于读写)。但是为了保证所有的读方法都能够正常工作,我们必须知道流中数据项所在的确切位置,因为极有可能将保存的 `double` 数据作为一个简单的字节序列、`char` 或其它类型读入。因此,我们必须:要么为文件中的数据采用固定的格式;要么将额外的信息保存到文件中,通过解析额外信息来确定数据的存放位置。注意,对象序列化和 XML (二者都在[附录:对象序列化](Appendix-Object-Serialization.md)中介绍)是存储和读取复杂数据结构的更简单的方式。