10.7 Java 1.1 的IO 流
10.7 Java 1.1 的IO 流
到这个时候,大家或许会陷入一种困境之中,怀疑是否存在
之所以在
下面这张表格分旧库与新库分别总结了信息发起与接收之间的对应关系。
Sources & Sinks:
Java 1.0 class
Corresponding Java 1.1 class
InputStream
Reader
converter: InputStreamReader
OutputStream
Writer
converter: OutputStreamWriter
FileInputStream
FileReader
FileOutputStream
FileWriter
StringBufferInputStream
StringReader
(no corresponding class)
StringWriter
ByteArrayInputStream
CharArrayReader
ByteArrayOutputStream
CharArrayWriter
PipedInputStream
PipedReader
PipedOutputStream
PipedWriter
我们发现即使不完全一致,但旧库组件中的接口与新接口通常也是类似的。
在
在下面这张表格中,对应关系比上一张表要粗糙一些。之所以会出现这个差别,是由类的组织造成的:尽管
Filters:
Java 1.0 class
Corresponding Java 1.1 class
FilterInputStream
FilterReader
FilterOutputStream
FilterWriter (abstract class with no subclasses)
BufferedInputStream
BufferedReader
(also has readLine( ))
BufferedOutputStream
BufferedWriter
DataInputStream
use DataInputStream
(Except when you need to use readLine( ), when you should use a BufferedReader)
PrintStream
PrintWriter
LineNumberInputStream
LineNumberReader
StreamTokenizer
StreamTokenizer
(use constructor that takes a Reader instead)
PushBackInputStream
PushBackReader
过滤器:
FilterInputStream FilterReader
FilterOutputStream FilterWriter(没有子类的抽象类)
BufferedInputStream BufferedReader(也有readLine())
BufferedOutputStream BufferedWriter
DataInputStream 使用DataInputStream(除非要使用readLine(),那时需要使用一个BufferedReader)
PrintStream PrintWriter
LineNumberInputStream LineNumberReader
StreamTokenizer StreamTokenizer(用构造器取代Reader)
PushBackInputStream PushBackReader
有一条规律是显然的:若想使用
为了将向
显然,
没有对应
DataOutputStream
File
RandomAccessFile
SequenceInputStream
特别未加改动的是
为体验新类的效果,下面让我们看看如何修改
//: 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");
}
// 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]);
} catch(IOException e) {
System.out.println("IO Exception");
}
}
} ///:~
大家一般看见的是转换过程非常直观,代码看起来也颇相似。但这些都不是重要的区别。最重要的是,由于随机访问文件已经改变,所以第
第
在
第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本身存在一个错误,如下述代码所示:
``` java
//: 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 pi\n");
out.writeBytes("This is pi/2:\n");
out.writeDouble(3.14159/2);
out.close();
DataInputStream in =
new DataInputStream(
new BufferedInputStream(
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());
}
} ///:~
看起来,我们在对一个
setIn(InputStream)
setOut(PrintStream)
setErr(PrintStream)
如果突然要在屏幕上生成大量输出,而且滚动的速度快于人们的阅读速度,输出的重定向就显得特别有用。在一个命令行程序中,如果想重复测试一个特定的用户输入序列,输入的重定向也显得特别有价值。下面这个简单的例子展示了这些方法的使用:
//: Redirecting.java
// Demonstrates the use of redirection for
// standard IO in Java 1.1
import java.io.*;
class Redirecting {
public static void main(String[] args) {
try {
BufferedInputStream in =
new BufferedInputStream(
new FileInputStream(
"Redirecting.java"));
// Produces deprecation message:
PrintStream out =
new PrintStream(
new BufferedOutputStream(
new FileOutputStream("test.out")));
System.setIn(in);
System.setOut(out);
System.setErr(out);
BufferedReader br =
new BufferedReader(
new InputStreamReader(System.in));
String s;
while((s = br.readLine()) != null)
System.out.println(s);
out.close(); // Remember this!
} catch(IOException e) {
e.printStackTrace();
}
}
} ///:~
这个程序的作用是将标准输入同一个文件连接起来,并将标准输出和错误重定向至另一个文件。
这是不可避免会遇到“反对”消息的另一个例子。用
Note:The constructor java.io.PrintStream(java.io.OutputStream) has been deprecated. 注意:不推荐使用构造器
java.io.PrintStream (java.io.OutputStream) 。
然而,无论