官方文档:https://docs.oracle.com/javase/tutorial/essential/io/index.html

Basic I/O

I/O Streams 包括了大部分简单的IO操作。
序列化将对象写入流从流中读出对象
I/O Streams 部分涵盖了 java.io 包中的大部分类。
File I/O 部分涵盖了 java.nio.file 包中的大部分类。

I/O Streams

一个 I/O Stream 代表了一个输入源和一个输出目标。 一个 流 可以代表不同种类的源和目标,包括:磁盘文件、设备,其他程序和内存数组。

Streams 支持不同种类的数据,包括:字节、基本数据类型、本地化的字符和对象。一部分 Streams 用来传递数据,其他的 Streams 可以操作和转换数据。

不管 Streams 的内部是如何工作的,所有流都为使用它们的程序提供了相同的简单模型:流是一系列数据。

程序用 input stream 从数据源读数据,one item at a time:

image.png

程序用 output stream 写数据到目标,one item at a time:

image.png

Streams 可以处理从基本数据类型到高级对象的所有种类的数据。

上面提到的 数据源 和 目标 可以是保存、生成或使用数据的任何事物。包括磁盘文件,另一个程序,外围设备,网络套接字或数组。

在下一部分,我们会使用最基本的流类型:字节流,来演示通用的I/O流操作。同时也会提供一个示例输入文件xanadu.txt,它的内容为:

  1. In Xanadu did Kubla Khan
  2. A stately pleasure-dome decree:
  3. Where Alph, the sacred river, ran
  4. Through caverns measureless to man
  5. Down to a sunless sea.

Byte Streams

程序使用 字节流 完成一次一个字节的输入和输出。所有字节流类都继承自 InputStream OutputStream .

为了了解字节流是如何工作的,我们先了解下文件I/O字节流:FileInputStream 和 FileOutputStream . 其他种类的字节流的使用方式类似,仅仅在于构造方式不同。

使用 Byte Streams

这里有一个例子程序,使用字节流copy xanadu.txt ,one byte at a time.

  1. import java.io.FileInputStream;
  2. import java.io.FileOutputStream;
  3. import java.io.IOException;
  4. public class CopyBytes {
  5. public static void main(String[] args) throws IOException {
  6. FileInputStream in = null;
  7. FileOutputStream out = null;
  8. try {
  9. in = new FileInputStream("xanadu.txt");
  10. out = new FileOutputStream("outagain.txt");
  11. int c;
  12. while ((c = in.read()) != -1) {
  13. out.write(c);
  14. }
  15. } finally {
  16. if (in != null) {
  17. in.close();
  18. }
  19. if (out != null) {
  20. out.close();
  21. }
  22. }
  23. }
  24. }

CopyBytes 循环 读输入流和写输出流 ,一次一个字节。如下图所示:

image.png

Always Close Streams

当一个 stream 不需要使用时,一定要关闭它。上面的示例中,在finally中关闭了 stream 。及时关闭能让我们避免严重的资源泄漏。

上面的示例中 stream 可能为 null,所以在调用它的 close 方法前进行了校验。

When Not to Use Byte Streams

CopyBytes看起来是一个常见的程序,但它是一种低级 I/O 操作的代表,我们应该极力避免。

假如 xanadu.txt 包括字符,最好的方式是使用 character streams,我们会在下一节讨论。

还有其他一些适用于更为复杂的数据类型的 流,字节流只适用于最原始的流。

但是我们为什么还要学习字节流呢?因为所有其他流类型都是基于字节流构建的。

Character Streams

Java 平台使用Unicode存储字节值。Character stream I/O 自动将内部格式转换成字符集 和 将字符集转换成内部格式。在Western语言环境中,本地字符集通常是ASCII的8位超集。

对于大多数应用程序来说,字符流不比字节流复杂。使用流类完成的输入和输出会自动转换为本地字符集和从本地字符集转换。使用字符流代替字节流的程序会自动适应本地字符集,并且可以进行国际化 - 所有这些都不需要程序员的额外努力。

如果国际化不是优先考虑事项,您可以简单地使用字符流类而不必过多关注字符集问题。之后,如果国际化成为优先事项,您的程序可以进行调整而无需进行大量重新编码。

Using Character Streams