Skip to content

Commit 0f0e11a

Browse files
committed
✓ 附录:IO 流 - 第四小节
1 parent 29ee624 commit 0f0e11a

1 file changed

Lines changed: 101 additions & 1 deletion

File tree

docs/book/Appendix-IO-Streams.md

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,22 +120,122 @@ I/O 流屏蔽了实际的 I/O 设备中处理数据的细节:
120120

121121
## Reader和Writer
122122

123+
Java 1.1 对基本的 I/O 流类库做了重大的修改。你初次遇到 `Reader``Writer` 时,可能会以为这两个类是用来替代 `InputStream``OutputStream` 的,但实际上并不是这样。尽管一些原始的“流”类库已经过时了(如果使用它们,编译器会发出警告),但是 `InputStream``OutputStream` 在面向字节 I/O 这方面仍然发挥着极其重要的作用,而 `Reader``Writer` 则提供兼容 Unicode 和面向字符 I/O 的功能。另外:
123124

125+
1. Java 1.1 往 `InputStream``OutputStream` 的继承体系中又添加了一些新类,所以这两个类显然是不会被取代的;
126+
127+
2. 有时我们必须把来自“字节”层级结构中的类和来自“字符”层次结构中的类结合起来使用。为了达到这个目的,需要用到“适配器(adapter)类”:`InputStreamReader` 可以把 `InputStream` 转换为 `Reader`,而 `OutputStreamWriter` 可以把 `OutputStream` 转换为 `Writer`
128+
129+
设计 `Reader``Writer` 继承体系主要是为了国际化。老的 I/O 流继承体系仅支持 8 比特的字节流,并且不能很好地处理 16 比特的 Unicode 字符。由于 Unicode 用于字符国际化(Java 本身的 `char` 也是 16 比特的 Unicode),所以添加 `Reader``Writer` 继承体系就是为了让所有的 I/O 操作都支持 Unicode。另外,新类库的设计使得它的操作比旧类库要快。
130+
131+
### 数据的来源和去处
132+
133+
几乎所有原始的 Java I/O 流类都有相应的 `Reader``Writer` 类来提供原生的 Unicode 操作。但是在某些场合,面向字节的 `InputStream``OutputStream` 才是正确的解决方案。特别是 `java.util.zip` 类库就是面向字节而不是面向字符的。因此,最明智的做法是尽量**尝试**使用 `Reader``Writer`,一旦代码没法成功编译,你就会发现此时应该使用面向字节的类库了。
134+
135+
下表展示了在两个继承体系中,信息的来源和去处(即数据物理上来自哪里又去向哪里)之间的对应关系:
136+
137+
| 来源与去处:Java 1.0 类 | 相应的 Java 1.1 类 |
138+
| :-------------------: | :--------------: |
139+
| `InputStream` | `Reader` <br/> 适配器:`InputStreamReader` |
140+
| `OutputStream` | `Writer` <br/> 适配器:`OutputStreamWriter` |
141+
| `FileInputStream` | `FileReader` |
142+
| `FileOutputStream` | `FileWriter` |
143+
| `StringBufferInputStream`(已弃用) | `StringReader` |
144+
| (无相应的类) | `StringWriter` |
145+
| `ByteArrayInputStream` | `CharArrayReader` |
146+
| `ByteArrayOutputStream` | `CharArrayWriter` |
147+
| `PipedInputStream` | `PipedReader` |
148+
| `PipedOutputStream` | `PipedWriter` |
149+
150+
总的来说,这两个不同的继承体系中的接口即便不能说完全相同,但也是非常相似的。
151+
152+
### 更改流的行为
153+
154+
对于 `InputStream``OutputStream` 来说,我们会使用 `FilterInputStream``FilterOutputStream` 的装饰器子类来修改“流”以满足特殊需要。`Reader``Writer` 的类继承体系沿用了相同的思想——但是并不完全相同。
155+
156+
在下表中,左右之间对应关系的近似程度现比上一个表格更加粗略一些。造成这种差别的原因是类的组织形式不同,`BufferedOutputStream``FilterOutputStream` 的子类,但 `BufferedWriter` 却不是 `FilterWriter` 的子类(尽管 `FilterWriter` 是抽象类,但却没有任何子类,把它放在表格里只是占个位置,不然你可能奇怪 `FilterWriter` 上哪去了)。然而,这些类的接口却又十分相似。
157+
158+
| 过滤器:Java 1.0 类 | 相应 Java 1.1 类 |
159+
| :--------------- | :-------------- |
160+
| `FilterInputStream` | `FilterReader` |
161+
| `FilterOutputStream` | `FilterWriter` (抽象类,没有子类) |
162+
| `BufferedInputStream` | `BufferedReader`(也有 `readLine()`) |
163+
| `BufferedOutputStream` | `BufferedWriter` |
164+
| `DataInputStream` | 使用 `DataInputStream`( 如果必须用到 `readLine()`,那你就得使用 `BufferedReader`。否则,一般情况下就用 `DataInputStream` |
165+
| `PrintStream` | `PrintWriter` |
166+
| `LineNumberInputStream` | `LineNumberReader` |
167+
| `StreamTokenizer` | `StreamTokenizer`(使用具有 `Reader` 参数的构造器) |
168+
| `PushbackInputStream` | `PushbackReader` |
169+
170+
有一条限制需要明确:一旦要使用 `readLine()`,我们就不应该用 `DataInputStream`(否则,编译时会得到使用了过时方法的警告),而应该使用 `BufferedReader`。除了这种情况之外的情形中,`DataInputStream` 仍是 I/O 类库的首选成员。
171+
172+
为了使用时更容易过渡到 `PrintWriter`,它提供了一个既能接受 `Writer` 对象又能接受任何 `OutputStream` 对象的构造器。`PrintWriter` 的格式化接口实际上与 `PrintStream` 相同。
173+
174+
Java 5 添加了几种 `PrintWriter` 构造器,以便在将输出写入时简化文件的创建过程,你马上就会见到它们。
175+
176+
其中一种 `PrintWriter` 构造器还有一个执行**自动 flush**[^2] 的选项。如果构造器设置了该选项,就会在每个 `println()` 调用之后,自动执行 flush。
177+
178+
### 未发生改变的类
179+
180+
有一些类在 Java 1.0 和 Java 1.1 之间未做改变。
181+
182+
| 以下这些 Java 1.0 类在 Java 1.1 中没有相应类 |
183+
| --- |
184+
| `DataOutputStream` |
185+
| `File` |
186+
| `RandomAccessFile` |
187+
| `SequenceInputStream` |
188+
189+
特别是 `DataOutputStream`,在使用时没有任何变化;因此如果想以可传输的格式存储和检索数据,请用 `InputStream``OutputStream` 继承体系。
124190

125191
<!-- Off By Itself: RandomAccessFile -->
126192
## RandomAccessFile类
127193

128194

195+
129196
<!-- Typical Uses of I/O Streams -->
130197
## IO流典型用途
131198

132199

200+
201+
### 缓冲输入文件
202+
203+
204+
205+
### 从内存输入
206+
207+
208+
209+
### 格式化内存输入
210+
211+
212+
213+
### 基本文件的输出
214+
215+
216+
217+
### 文本文件输出快捷方式
218+
219+
220+
221+
### 存储和恢复数据
222+
223+
224+
225+
### 读写随机访问文件
226+
227+
228+
133229
<!-- Summary -->
134230
## 本章小结
135231

232+
233+
136234
[^1]: 很难说这就是一个很好的设计选择,尤其是与其它编程语言中简单的 I/O 类库相比较。但它确实是如此选择的一个正当理由。
137235

138-
[^2]: XML 是另一种方式,可以解决在不同计算平台之间移动数据,而不依赖于所有平台上都有 Java 这一问题。XML 将在[附录:对象序列化](./Appendix-Object-Serialization.md)一章中进行介绍。
236+
[^2]: 译者注:“flush” 直译是“清空”,意思是把缓冲中的数据清空,输送到对应的目的地(如文件和屏幕)。
237+
238+
[^3]: XML 是另一种方式,可以解决在不同计算平台之间移动数据,而不依赖于所有平台上都有 Java 这一问题。XML 将在[附录:对象序列化](./Appendix-Object-Serialization.md)一章中进行介绍。
139239

140240
<!-- 分页 -->
141241

0 commit comments

Comments
 (0)