在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
public final static InputStream in = nullInputStream();
public final static PrintStream out = nullPrintStream();
public final static PrintStream err = nullPrintStream();
他们都是静态属性的字段,因此能直接用System类直接调用,这些字段实际上private static void initializeSystemClass()中初始化的:
[java] view plaincopy
private static void initializeSystemClass() {
FileInputStream fdIn = new FileInputStream(FileDescriptor.in);
FileOutputStream fdOut = new FileOutputStream(FileDescriptor.out);
FileOutputStream fdErr = new FileOutputStream(FileDescriptor.err);
setIn0(new BufferedInputStream(fdIn));
setOut0(new PrintStream(new BufferedOutputStream(fdOut, 128), true));
setErr0(new PrintStream(new BufferedOutputStream(fdErr, 128), true));
}
FileDescriptor.out,FileDescriptor.in和FileDescriptor.err其实是
[java] view plaincopy
public static final FileDescriptor in = standardStream(0);
public static final FileDescriptor out = standardStream(1);
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
byte[] b = new byte[1024];
int count = System.in.read(b);
System.out.println(new String(b, 0, count));
可以说如果单纯的直接对System.in操作来接受控制台的输入,我们能做到的太少,因此我们要接受控制台的输入我们需要对它进行包装,其中一种包装方式就是用其他的方式进行包装,由于装饰流DataInputStream能够操作基本数据类型,而且他的构造方法是DataInputStream(InputStream in)。那我们里所当然的认为这样操作:
[java] view plaincopy
DataInputStream stdin=new DataInputStream((System.in));
然后调用其中的方法来读取基本数据类型就可以,但是很遗憾,这么不会得到理想的结果,本人并没有想明白其中的原因,还请大神看了这篇文章以后做一个解释。另外值得一说的是,类InputStreamReader类是连接字节流和字符流的桥梁,我们可以通过这个类用缓冲字符流对System.in进行包装,如下:
[java] view plaincopy
BufferedReader buf=new BufferedReader(new InputStreamReader(System.in));
String s=buf.readLine();
System.out.println(s);
这么的还是能得到理想的结果的。那么我们到底怎么从控制台读取各种基本数据类型呢?这就是初学者一上手用到的Scanner类。
(2)用Scanner包装System.in
通过import类java.util.Scanner我们就可以使用这个类,这个类有一个构造方法Scanner(InputSteam in),并且这个类里面有操作各种数据类型的方法。因此我们可以将其包装成一个Scanner类引用,然后调用方法来从控制台读取基本数据。如下:
[java] view plaincopy
Scanner in=new Scanner(System.in);
int tt=in.nextInt();
System.out.println(tt);
这段代码大家再熟悉不过了吧,就不多说了,对System.in相信已经很熟悉了,下面再说说另外两种标准I/O。
System.out和System.err的使用
这两个都是控制台输出。从源码可以看到,他们都是PrintStream类字段,是已经包装过的,我们可以调用方法println等对他们进行输出,那么它们有什么区别呢?先看看这段代码:
[java] view plaincopy
import java.lang.*;
import java.util.*;
import java.io.*;
public class fanxing{
public static void main(String []args){
System.out.println("hello world");
System.err.println("hello world");
}
}
运行结果如下:
看到差异了吧,这是因为out是正常输出,而err是错误输出,错误的应该具有警示作用,因此用err输出的内容是错误的字体。下面说说他们的差别。系统既然可以默认,程序就能修改,也就是从定向。就是说通过设置,让System.out把信息输出到你想要的地方,比如文件,也就成了日志文件。一般的信息和错误信息是不同的,那必须得分开。比如你可以把一般的信息和错误信息打印到不同的文件里面,你就可以很快找到错误信息,而不至于被淹没在大量的一般信息里面。这就是为什么你的系统日志分一般日志和错误日志。 还有一个区别是,out是缓存输出的,err是不缓存的,因为它紧急。接下来说说重定向。
3.重定向
标准I/O默认的是控制台输入输出,那么我们可以将他们修改,这就是重定向,对于重定向System有3种方法,分别是setIn(InputStream),setOut(PintStream),setErr(PrintStream)。我们可以将他们重定向到文件里,这就实现了我们常见的日志系统,如下代码:
[java] view plaincopy
package jdk.lang;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
public class SystemIOE {
public static void main(String[] args) throws Exception {
redirect();
helloIO();
}
private static void helloIO() throws IOException {
System.out.println("Hello Out");
System.err.println("Hello Error");
byte[] b = new byte[1024];
int count = System.in.read(b);
System.out.println(new String(b, 0, count));
}
public static void redirect() throws FileNotFoundException {
InputStream in = new BufferedInputStream(new FileInputStream(new File(
"c:/in.txt")));
System.setIn(in);
PrintStream out = new PrintStream(new FileOutputStream(new File(
"c:/out.log")));
System.setOut(out);
PrintStream err = new PrintStream(new FileOutputStream(new File(
"c:/err.log")));
System.setErr(err);
}
}
关于JAVA的标准I/O就说这么多吧。
参考文章:Java System 类详解 - in, out, errhttp://jackycheng2007.iteye.com/blog/1473625