按照标准I/O模型,Java提供了System.in、System.out、和System.err。查看System类的源码,我们可以发现,System.out和System.err是PrintStream对象,System.in却是没有未经包装的InputStream对象。所以,我们在读取System.in之前需要对其进行包装。
通常我们会使用readLine()一次一行地读取,为此,我们将System.in包装成BufferedReader。在创建BufferedReader时,我们需要使用InputStreamReader将System.in转换成Reader。InputStreamReader是一个适配器,接收InputStream对象并将其转换成Reader对象。
下面的例子将回显输入的每一行:
public class Echo { public static void main(String[] args) throws IOException{ BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); String s; while((s = stdin.readLine()) != null && s.length() != 0) { System.out.println(s); } } } 将System.out转换成PrintWriterSystem.out是一个PrintStream,而PrintStream是一个OutputStream。PrintWriter恰好有一个可以接受OutputStream作为参数的构造器。
public class ChangeSystemOut { public static void main(String[] args) { PrintWriter out = new PrintWriter(System.out, true);//若是不设置为true则看不到输出 out.println("Hello World!"); } } /* output: Hello World! */ 标准I/O重定向Java的System类提供了一些简单的静态方法调用,以允许我们对标准输入、输出和错误I/O流进行重定向:
如果我们突然在显示器上创建大量输出,而且这些输出滚动得太快以至于无法阅读,此时重定向输出就显得很重要(我们可以将输出定向至其他地方一般为输出到一个文件中)。或者,我们想重复测试某个特定输入样例,此时重定向输入就很有必要(如将标准输入重定向至一个文件)。下面简单演示这些方法的使用。
public class Redirecting { public static void main(String[] args) throws IOException { PrintStream console = System.out; //带缓冲的输入流和输出流对象 BufferedInputStream in = new BufferedInputStream(new FileInputStream("Redirecting.java")); PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("test.out"))); System.setIn(in); //重定向标准输入为Redirecting.java文件 System.setOut(out); //重定向标准输出为test.out文件 System.setErr(out); //重定向标准错误未test.out //读取重定向后的标准输入即Redirecting.java文件 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String s; while((s = br.readLine()) != null) { //将读取的数据重定向输出至test.out中 System.out.println(s); } out.close(); System.setOut(console); } }这个程序将标准输入附接到文件上,并将标准输出和标准错误重定向到另外一个文件中。注意,在程序的开头处存储了对最初的System.out对象的引用,并且在结尾处将系统输出恢复到了该对象上。
I/O重定向操作的是字节流而不是字符流,所以使用InputStream和OutputStream。
新I/O(nio) 通道和缓冲器JDK 1.4中的java.nio.*包中引入了新的Java I/O类库,目的在于提高速度。实际上,旧的I/O包已经使用nio重新实现过,以便充分利用这种速度提高。
速度的提高来自于所使用的结构更接近于操作系统执行I/O的方式:通道和缓冲器。我们可以将通道想象成包含煤层(数据)的矿藏,而缓冲器则是派送到矿藏的卡车。卡车满载而归,我们再从卡车上获得煤矿。即,我们没有直接与通道交互;我们只是和缓冲器交互,缓冲器与通道交互。所以,通道是向缓冲器发送数据和从缓冲器获得数据。
唯一直接与通道交互的缓冲器是ByteBuffer。查看JDK文档可以知道,它是一个基础的类也是一个抽象类:通过告知分配多少存储空间来创建一个ByteBuffer对象,并且还有一个方法集,用以原始字节形式或基本数据类型输出和读取数据。包含的这些方法也是抽象方法,没有办法输出和读取对象。
旧I/O类库中有三个类被修改了,用以产生FileChannel。这三个类为FIleInputStream、FileOutputStream以及用于随机读写的RandomAccessFile。这些都是字节操纵流,与底层的nio性质一致。Reader和Writer这种字符模式类不能用于产生通道,但是java.nio.channels.Channels类提供了实用方法,用以在通道中产生Reader和Writer。