Java I/O Streams

原文:https://docs.oracle.com/javase/tutorial/essential/io/streams.html

前言

Java中基础的I/O知识包括两方面:I/O Streams 和 File I/O。这部分学习I/O Streams。

I/O Streams

I/O Streams 大大简化了IO操作。
java.io 包中包含了所有 I/O Streams 操作类。

什么是I/O Streams

一个 I/O Stream 代表了一个输入源 或 一个输出目标。源和目标可以是:磁盘文件、设备,其他程序和内存数组。Streams 支持不同种类的数据,包括:字节、基本数据类型、本地化的字符和对象。

不管 Streams 的内部是如何工作的,所有流都为使用它们的程序提供了相同的简单模型:流是一系列数据。程序用 input stream 从数据源读数据,one item at a time:
在这里插入图片描述
程序用 output stream 写数据到目标,one item at a time:
在这里插入图片描述
Streams 可以处理从基本数据类型到高级对象的所有种类的数据。

Byte Streams

程序使用 字节流 完成一次一个字节的输入和输出。所有字节流类都继承自 InputStream 和 OutputStream 。它是最基础的 I/O 操作方式。

Character Streams

Java 平台使用Unicode存储字节值。Character stream I/O 自动将内部格式转换成字符集 和 将字符集转换成内部格式。所有的字符流类都继承自Reader 和 Writer。

字符流通常是字节流的包装器。字符流使用字节流来执行物理I/O,而字符流处理字符和字节之间的转换。例如,在使用FileReader时,它调用了FileInputStream;在使用FileWriter时,它调用了FileOutputStream。

有两个多功能的流类:InputStreamReader 和 OutputStreamWriter,可以作为字节流和字符流相互转换的桥。

字符I/O通常以比单个字符更大的单位出现。一个常见的单位是行:一串字符,末尾有一个行终止符。我们必须使用之前未见过的两个类:BufferedReader 和 PrintWriter。

Buffered Streams

到目前为止,我们看到的大部分示例都是使用无缓冲的I/O。这意味着每个读或写请求都由底层操作系统直接处理。这使得程序低效,因为每个这样的请求经常会触发磁盘访问、网络活动或一些相对昂贵的其他操作。

为了减少这种开销,Java平台实现了带缓冲的I/O流。缓冲输入流从称为缓冲区的存储区取数据;仅当缓冲区为空时才调用本机的输入API。类似的,缓冲输出流将数据写入缓冲区,并且仅在缓冲区已满时才调用本机的输出API。

程序可以使用我们现在多次使用的包装用法将无缓冲的流转换为缓冲流,其中无缓冲的流对象被传递给缓冲流类的构造函数。示例代码:

inputStream = new BufferedReader(new FileReader("xanadu.txt"));
outputStream = new BufferedWriter(new FileWriter("characteroutput.txt"));

还有4个缓冲流类用于包装无缓冲流:BufferedInputStream 和 BufferedOutputStream 用于创建缓冲字节流,而BufferedReader 和 BufferedWriter 用于创建缓冲字符流。

刷新缓冲流

在关键点写出缓冲区通常是有意义的,而无需等待它填满。这称为刷新缓冲区。
一些缓冲的输入类支持autoflush,由可选的构造函数参数指定。启用autoflush时,某些键事件会导致缓冲刷新。例如,PrintWriter在每次调用println 和 format时自动刷新。
如果想要手动刷新,则需要调用它的flush方法。该flush方法在任何带缓冲的输出流上都有效。

扫描和格式化

编码 I/O 通常涉及到转义和格式化。为了帮助你完成这些杂务,Java平台提供了两个API:scanner 和 formatting。
实现了格式化的类有PrintWriter(字符流类)和PrintStream(字节流类)。
PrintStream的唯一使用场景是System.out和System.err。当你需要创建格式化输出流时,请使用PrintWriter。
对于所有的字节流和字符流对象,简单的字节和字符输出,PrintStream和PrintWriter都实现了一个标准的write方法集。另外,PrintStream和PrintWriter使用相同的方法集将内部数据格式化输出。提供了两个级别的格式化:

  • print 和 println 以标准的方式格式化单个值。
  • format 可以格式化基于字符串的任意数据的值,具有许多拥有精确格式化的选项。

Command Line I/O

程序通常从命令行运行,并在命令行中与用户交互。Java平台以两种方式支持这种交互:通过标准流和控制台。

Data Streams

数据流支持基本数据类型(boolean、char、byte、short、int、long、float和double)和字符串的二进制I/O 。
所有数据流都实现了DataInput 或 DataOutput。最广泛使用的两个实现类是:DataInputStream 和 DataOutputStream 。

Object Streams

正如数据流支持基本数据类型I/O一样,对象流也支持对象的I/O。大部分,但不是所有,支持实现了Serializable的标准类对象。
对象流类有ObjectInputStream 和 ObjectOutputStream。它们实现了ObjectInput 和 ObjectOutput。
而ObjectInput和ObjectOutput是DataInput和DataOutput的子类。这意味着所有的数据流方法,也在对象流中可用。所以,对象流可以包含原始值和对象值的混合。价格可以是BigDecimal对象,发票日期可以是Calendar。

假如 readObject() 没有返回预期的对象类型,强制将其转换为指定的类型可能会抛出一个ClassNotFoundException。

复杂对象的输出和输入
writeObject 和 readObject 方法使用起来非常简单,但是它们包含了非常复杂的对象管理逻辑。这对像Calendar这样的类来说并不重要,它只封装了原始值。但是一些对象包含了其他对象的引用。下图展示了复杂对象的输入和输出过程。
在这里插入图片描述

展开阅读全文

没有更多推荐了,返回首页