JAVa标准I/O详解

   在JAVA的类库java.lang中我们经常用到System类的System.in,,System.out这种控制台输入输出,这就是所谓的标准流。本文试着对标准I/0做一个比较详细的说明。

     1.标准I/0源码

      JAVA里面提供了3中标准I/0模型,即System.in,System.out,System.err。我们先看看这几种模型的源码:

      

[java] view plaincopy在CODE上查看代码片

  1. public final static InputStream in = nullInputStream();    

  2. public final static PrintStream out = nullPrintStream();    

  3. public final static PrintStream err = nullPrintStream();    

      他们都是静态属性的字段,因此能直接用System类直接调用,这些字段实际上private static void initializeSystemClass()中初始化的:

[java] view plaincopy在CODE上查看代码片

  1. private static void initializeSystemClass() {    

  2.     

  3.     FileInputStream fdIn = new FileInputStream(FileDescriptor.in);    

  4.     FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);    

  5.     FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);    

  6.     setIn0(new BufferedInputStream(fdIn));    

  7.     setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));    

  8.     setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true));    

  9.     

  10. }    


    FileDescriptor.out,FileDescriptor.in和FileDescriptor.err其实是 

[java] view plaincopy在CODE上查看代码片

  1. public static final FileDescriptor in = standardStream(0);    

  2. public static final FileDescriptor out = standardStream(1);    

  3. public static final FileDescriptor err = standardStream(2);    


     明显可以看出它们都是标准流,即常见的控制台输入输出,这也是系统默认的输入输出。接下来看看它们的用法与区别。

     2.标准I/0的使用

     System.in的使用

         (1)从System.in.read()说起

                 为什么从这说起呢?因为字段System.in事实上是InputStream类,我们自然想到Inputstream类里面有什么读取的方法。可以看到有两个,一个是read(),另外一个是read(byte [])。我们经常使用的int in=System.in.read()就表示的“从控制台读取一个字节的内容,并且把它的ASCII码作为返回值”。因此,写这句代码以后我们无论是控制台输入abc还是只输入a,变量in得到的值都会是97。接着看看另外一个read(byte []),看看API文档,它的含义是:从控制台读取一个字节数组,并且返回读取的字节数组的数量。具体的看看下面的例子就明白了,在main函数里面放上下面这段代码,然后从控制台敲入一串字符,看看结果。

[java] view plaincopy在CODE上查看代码片

  1. byte[] b = new byte[1024];    

  2.             int count = System.in.read(b);    

  3.             System.out.println(new String(b, 0, count));   


               可以说如果单纯的直接对System.in操作来接受控制台的输入,我们能做到的太少,因此我们要接受控制台的输入我们需要对它进行包装,其中一种包装方式就是用其他的方式进行包装,由于装饰流DataInputStream能够操作基本数据类型,而且他的构造方法是DataInputStream(InputStream in)。那我们里所当然的认为这样操作:

[java] view plaincopy在CODE上查看代码片

  1. DataInputStream stdin=new DataInputStream((System.in));  


              然后调用其中的方法来读取基本数据类型就可以,但是很遗憾,这么不会得到理想的结果,本人并没有想明白其中的原因,还请大神看了这篇文章以后做一个解释。另外值得一说的是,类InputStreamReader类是连接字节流和字符流的桥梁,我们可以通过这个类用缓冲字符流对System.in进行包装,如下:

[java] view plaincopy在CODE上查看代码片

  1. BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));  

  2.          String s=buf.readLine();  

  3.          System.out.println(s);  


               这么的还是能得到理想的结果的。那么我们到底怎么从控制台读取各种基本数据类型呢?这就是初学者一上手用到的Scanner类。

         (2)用Scanner包装System.in

                通过import类java.util.Scanner我们就可以使用这个类,这个类有一个构造方法Scanner(InputSteam in),并且这个类里面有操作各种数据类型的方法。因此我们可以将其包装成一个Scanner类引用,然后调用方法来从控制台读取基本数据。如下:

[java] view plaincopy在CODE上查看代码片

  1. Scanner in=new Scanner(System.in);  

  2.             int tt=in.nextInt();  

  3.             System.out.println(tt);  


                这段代码大家再熟悉不过了吧,就不多说了,对System.in相信已经很熟悉了,下面再说说另外两种标准I/O。

    System.out和System.err的使用

         这两个都是控制台输出。从源码可以看到,他们都是PrintStream类字段,是已经包装过的,我们可以调用方法println等对他们进行输出,那么它们有什么区别呢?先看看这段代码:

[java] view plaincopy在CODE上查看代码片

  1. import java.lang.*;  

  2. import java.util.*;  

  3. import java.io.*;  

  4. public class fanxing{  

  5.     public static void main(String []args){  

  6.             System.out.println("hello world");  

  7.             System.err.println("hello world");  

  8.     }  

  9. }  

        运行结果如下:

JAVa标准I/O详解
        

           看到差异了吧,这是因为out是正常输出,而err是错误输出,错误的应该具有警示作用,因此用err输出的内容是错误的字体。下面说说他们的差别。系统既然可以默认,程序就能修改,也就是从定向。就是说通过设置,让System.out把信息输出到你想要的地方,比如文件,也就成了日志文件。一般的信息和错误信息是不同的,那必须得分开。比如你可以把一般的信息和错误信息打印到不同的文件里面,你就可以很快找到错误信息,而不至于被淹没在大量的一般信息里面。这就是为什么你的系统日志分一般日志和错误日志。 还有一个区别是,out是缓存输出的,err是不缓存的,因为它紧急。接下来说说重定向。

     3.重定向

     标准I/O默认的是控制台输入输出,那么我们可以将他们修改,这就是重定向,对于重定向System有3种方法,分别是setIn(InputStream),setOut(PintStream),setErr(PrintStream)。我们可以将他们重定向到文件里,这就实现了我们常见的日志系统,如下代码:

[java] view plaincopy在CODE上查看代码片

  1. package jdk.lang;    

  2.     

  3. import java.io.BufferedInputStream;    

  4. import java.io.File;    

  5. import java.io.FileInputStream;    

  6. import java.io.FileNotFoundException;    

  7. import java.io.FileOutputStream;    

  8. import java.io.IOException;    

  9. import java.io.InputStream;    

  10. import java.io.PrintStream;    

  11.     

  12. public class SystemIOE {    

  13.     public static void main(String[] args) throws Exception {    

  14.         redirect();    

  15.         helloIO();    

  16.     }    

  17.     

  18.     private static void helloIO() throws IOException {    

  19.         System.out.println("Hello Out");    

  20.         System.err.println("Hello Error");    

  21.         byte[] b = new byte[1024];    

  22.         int count = System.in.read(b);    

  23.         System.out.println(new String(b, 0, count));    

  24.     }    

  25.     

  26.     public static void redirect() throws FileNotFoundException {    

  27.         InputStream in = new BufferedInputStream(new FileInputStream(new File(    

  28.                 "c:/in.txt")));    

  29.         System.setIn(in);    

  30.         PrintStream out = new PrintStream(new FileOutputStream(new File(    

  31.                 "c:/out.log")));    

  32.         System.setOut(out);    

  33.         PrintStream err = new PrintStream(new FileOutputStream(new File(    

  34.                 "c:/err.log")));    

  35.         System.setErr(err);    

  36.     }    

  37. }    


      关于JAVA的标准I/O就说这么多吧。


      参考文章:Java System 类详解 - in, out, errhttp://jackycheng2007.iteye.com/blog/1473625


你可能感兴趣的:(JAVa标准I/O详解)