友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第76部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
发起&接收:Java 1。0 类 对应的 Java 1。1 类
Sources & Sinks: Corresponding Java 1。1 class
Java 1。0 class
305
…………………………………………………………Page 307……………………………………………………………
I n p u t S t r e a m R e a d e r
converter: InputStreamReader
O u t p u t S t r e a m W r i t e r
converter: OutputStreamWriter
F i l e I n p u t S t r e a m F i l e R e a d e r
F i l e O u t p u t S t r e a m F i l e W r i t e r
StringBufferInputStream S t r i n g R e a d e r
(no corresponding class) S t r i n g W r i t e r
ByteArrayInputStream C h a r A r r a y R e a d e r
ByteArrayOutputStream C h a r A r r a y W r i t e r
P i p e d I n p u t S t r e a m P i p e d R e a d e r
P i p e d O u t p u t S t r e a m P i p e d W r i t e r
我们发现即使不完全一致,但旧库组件中的接口与新接口通常也是类似的。
10。7。2 修改数据流的行为
在Java 1。0 中,数据流通过FilterInputStream 和FilterOutputStream 的“装饰器”(Decorator)子类适
应特定的需求。Java 1。1 的 IO流沿用了这一思想,但没有继续采用所有装饰器都从相同“filter”(过滤
器)基础类中衍生这一做法。若通过观察类的层次结构来理解它,这可能令人出现少许的困惑。
在下面这张表格中,对应关系比上一张表要粗糙一些。之所以会出现这个差别,是由类的组织造成的:尽管
BufferedOutputStream 是 FilterOutputStream 的一个子类,但是BufferedWriter 并不是FilterWriter 的
子类(对后者来说,尽管它是一个抽象类,但没有自己的子类或者近似子类的东西,也没有一个“占位符”
可用,所以不必费心地寻找)。然而,两个类的接口是非常相似的,而且不管在什么情况下,显然应该尽可
能地使用新版本,而不应考虑旧版本(也就是说,除非在一些类中必须生成一个Stream,不可生成 Reader
或者Writer)。
过滤器:Java 1。0 类 对应的 Java 1。1 类
FilterInputStream FilterReader
FilterOutputStream FilterWriter (没有子类的抽象类)
BufferedInputStream BufferedReader (也有readLine())
BufferedOutputStream BufferedWriter
DataInputStream 使用DataInputStream (除非要使用readLine(),那时需要使用一个BufferedReader)
PrintStream PrintWriter
LineNumberInputStream LineNumberReader
StreamTokenizer StreamTokenizer (用构建器取代Reader)
PushBackInputStream PushBackReader
有一条规律是显然的:若想使用readLine(),就不要再用一个DataInputStream 来实现(否则会在编译期得
到一条出错消息),而应使用一个 BufferedReader。但除这种情况以外,DataInputStream 仍是Java 1。1
IO库的“首选”成员。
为了将向PrintWriter 的过渡变得更加自然,它提供了能采用任何OutputStream 对象的构建器。
PrintWriter 提供的格式化支持没有 PrintStream 那么多;但接口几乎是相同的。
10。7。3 未改变的类
显然,Java 库的设计人员觉得以前的一些类毫无问题,所以没有对它们作任何修改,可象以前那样继续使用
它们:
没有对应Java 1。1 类的Java 1。0 类
306
…………………………………………………………Page 308……………………………………………………………
DataOutputStream
File
RandomAccessFile
SequenceInputStream
特别未加改动的是 DataOutputStream,所以为了用一种可转移的格式保存和获取数据,必须沿用
InputStream和 OutputStream 层次结构。
10。7。4 一个例子
为体验新类的效果,下面让我们看看如何修改 IOStreamDemo。java示例的相应区域,以便使用Reader 和
Writer 类:
//: NewIODemo。java
// Java 1。1 IO typical usage
import java。io。*;
public class NewIODemo {
public static void main(String'' args) {
try {
// 1。 Reading input by lines:
BufferedReader in =
new BufferedReader(
new FileReader(args'0'));
String s; s2 = new String();
while((s = in。readLine())!= null)
s2 += s + 〃n〃;
in。close();
// 1b。 Reading standard input:
BufferedReader stdin =
new BufferedReader(
new InputStreamReader(System。in));
System。out。print(〃Enter a line:〃);
System。out。println(stdin。readLine());
// 2。 Input from memory
StringReader in2 = new StringReader(s2);
int c;
while((c = in2。read()) != …1)
System。out。print((char)c);
// 3。 Formatted memory input
try {
DataInputStream in3 =
new DataInputStream(
// Oops: must use deprecated class:
new StringBufferInputStream(s2));
while(true)
System。out。print((char)in3。readByte());
} catch(EOFException e) {
System。out。println(〃End of stream〃);
307
…………………………………………………………Page 309……………………………………………………………
}
// 4。 Line numbering & file output
try {
LineNumberReader li =
new LineNumberReader(
new StringReader(s2));
BufferedReader in4 =
new BufferedReader(li);
PrintWriter out1 =
new PrintWriter(
new BufferedWriter(
new FileWriter(〃IODemo。out〃)));
while((s = in4。readLine()) != null )
out1。println(
〃Line 〃 + li。getLineNumber() + s);
out1。close();
} catch(EOFException e) {
System。out。println(〃End of stream〃);
}
// 5。 Storing & recovering data
try {
DataOutputStream out2 =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(〃Data。txt〃)));
out2。writeDouble(3。14159);
out2。writeBytes(〃That was pi〃);
out2。close();
DataInputStream in5 =
new DataInputStream(
new BufferedInputStream(
new FileInputStream(〃Data。txt〃)));
BufferedReader in5br =
new BufferedReader(
new InputStreamReader(in5));
// Must use DataInputStream for data:
System。out。println(in5。readDouble());
// Can now use the 〃proper〃 readLine():
System。out。println(in5br。readLine());
} catch(EOFException e) {
System。out。println(〃End of stream〃);
}
// 6。 Reading and writing random access
// files is the same as before。
// (not repeated here)
} catch(FileNotFoundException e) {
System。out。println(
〃File Not Found:〃 + args'1');
308
…………………………………………………………Page 310……………………………………………………………
} catch(IOException e) {
System。out。println(〃IO Exception〃);
}
}
} ///:~
大家一般看见的是转换过程非常直观,代码看起来也颇相似。但这些都不是重要的区别。最重要的是,由于
随机访问文件已经改变,所以第6 节未再重复。
第 1 节收缩了一点儿,因为假如要做的全部事情就是读取行输入,那么只需要将一个 FileReader 封装到
BufferedReader 之内即可。第 1b 节展示了封装System。in,以便读取控制台输入的新方法。这里的代码量增
多了一些,因为System。in 是一个DataInputStream,而且BufferedReader 需要一个Reader 参数,所以要
用 InputStreamReader来进行转换。
在 2 节,可以看到如果有一个字串,而且想从中读取数据,只需用一个StringReader 替换
StringBufferInputStream,剩下的代码是完全相同的。
第 3 节揭示了新 IO流库设计中的一个错误。如果有一个字串,而且想从中读取数据,那么不能再以任何形式
使用StringBufferInputStream。若编译一个涉及StringBufferInputStream 的代码,会得到一条“反对”
消息,告诉我们不要用它。此时最好换用一个 StringReader。但是,假如要象第3 节这样进行格式化的内存
输入,就必须使用 DataInputStream——没有什么“DataReader”可以代替它——而DataInputStream 很不
幸地要求用到一个 InputStream 参数。所以我们没有选择的余地,只好使用编译器不赞成的
StringBufferInputStream 类。编译器同样会发出反对信息,但我们对此束手无策(注释②)。
StringReader 替换StringBufferInputStream,剩下的代码是完全相同的。
②:到你现在正式使用的时候,这个错误可能已经修正。
第4 节明显是从老式数据流到新数据流的一个直接转换,没有需要特别指出的。在第 5 节中,我们被强迫使
用所有的老式数据流,因为DataOutputStream 和 DataInputStream 要求用到它们,而且没有可供替换的东
西。然而,编译期间不会产生任何“反对”信息。若不赞成一种数据流,通常是由于它的构建器产生了一条
反对消息,禁止我们使用整个类。但在DataInputStream 的情况下,只有readLine()是不赞成使用的,因为
我们最好为 readLine()使用一个 BufferedReader (但为其他所有格式化输入都使用一个
DataInputStream)。
若比较第5 节和 IOStreamDemo。java 中的那一小节,会注意到在这个版本中,数据是在文本之前写入的。那
是由于Java 1。1 本身存在一个错误,如下述代码所示:
//: IOBug。java
// Java 1。1 (and higher?) IO Bug
import java。io。*;
public class IOBug {
public static void main(String'' args)
throws Exception {
DataOutputStream out =
new DataOutputStream(
new BufferedOutputStream(
new FileOutputStream(〃Data。txt〃)));
out。writeDouble(3。14159);
out。writeBytes(〃That was the value of pin〃);
out。writeBytes(〃This is pi/2:n〃);
out。writeDouble(3。14159/2);
out。close();
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
309
…………………………………………………………Page 311……………………………………………………………
new FileInputStream(〃Data。txt〃)));
BufferedReader inbr =
new BufferedReader(
new InputStreamReader(in));
// The doubles written BEFORE the line of text
// read back correctly:
System。out。println(in。readDouble());
// Read the lines of text:
System。out。println(inbr。readLine());
System。out。println(inbr。readLine());
// Trying to read the doubles after the line
// produces an end…of…file exception:
System。out。println(in。readDouble());
}
} ///:~
看起来,我们在对一个 writeBytes()的调用之后写入的任何东西都不是能够恢复的。这是一个十分有限的错
误,希望在你读到本书的时候已获得改正。为检测是否改正,请运行上述程序。若没有得到一个违例,而且
值都能正确打印出来,就表明已经改正。
10。7。5 重导向标准 IO
Java 1。1 在System 类中添加了特殊的方法,允许我们重新定向标准输入、输出以及错误 IO流。此时要用到
下述简单的静态方法调用:
setIn(InputStream)
setOut(PrintStream)
setErr(PrintStream)
如果突然要在屏幕上生成大量输出,而且滚动的速度快于人们的阅读速度,输出的重定向就显得特别有用。
在一个命令行程序中,如果想重复测试一个特定的用户输入序列,输入的重定向也显得特别有价值。下面这
个简单的例子展示了这些方法的使用:
//: Redirecting。java
// Demonstrates the
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!