Java IO 6- BufferedReader,Scanner键盘输入和err,in,out
err/in/out
和C/C++一样,Java也有 err/in/out 的概念,Java中是由系统类 System类 给出的。
含义如下:
// 错误输出
public static final PrintStream err = null;
// 标准输入(键盘)
public static final InputStream in = null;
// 标准输出(显示器)
public static final PrintStream out = null;
System.err只是作为一个保留的属性而存在,现在几乎用不到。
由于System.out是PrintStream(字节打印流)的实例化对象,而PrintStream又是OutputStream的子类,所以可以直接使用System.out直接为OutputStream实例化,这个时候的OutputStream输出的位置将变为屏幕。
System.in对应的类型是InputStream,而这种输入流指的是由用户通过键盘进行输入(用户输入)。
java本身并没有直接的用户输入处理,如果要想实现这种操作,必须使用java.io的模式来完成。
如下面的例子:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class Test {
public static void main(String[] args) throws IOException {
// System.in方式的键盘输入
InputStream input = System.in;
// 打开内存流
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] data = new byte[10];
System.out.print("input:");
int len = 0;
while((len = input.read(data)) != -1) {
out.write(data, 0, len);
// 如果本次读入的字节没把数组装满,证明输入完了
if(len < data.length) {
break;
}
}
input.close();
out.close();
// 打印存储在内存中的内容
System.out.println("output:"+new String(out.toByteArray()));
}
}
虽然上面的例子可以实现从键盘输入并取到输入的内容,可这并绝不是我们常规的做法。
键盘接收数据
1. BufferedReader类
BufferedReader类属于一个缓冲的输入流,它是一个字符流的操作对象。
在java中对于缓冲流也分为两类:字节缓冲流(BufferedInputStream)、字符缓冲流(BufferedReader)。
我们通过BufferedReader类的readLine()方法来获取键输入的数据。
// 这个方法可以读取键盘输入的一行数据,以回车为结尾
public String readLine() throws IOException
在使用BuffeedReader之前我们再看一下它的的构造方法。
public BufferedReader(Reader in)
显然,它需要一个传入 Reander类 的参数。
而System.in是InputStream类的子类,所以就不能直接使用了,但是我们可以使用用InputStreamReader类(转换流)将 System.in 转换为一个 Reader 类来使用。
我们看下面的例子:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Test {
public static void main(String[] args) throws IOException {
// BufferedReader字符缓冲输入流
BufferedReader buf = new BufferedReader(new InputStreamReader(System.in));
System.out.print("input:");
String str = buf.readLine();
System.out.print("output:"+str);
}
}
这比起上一节中的内存流配合System.in接受键盘数据的方式简单多了。bufferedReader解决了system.in原始化操作(先写到内存中,再从内存中进行读取转换)的复杂操作。
可是,这种方法自从JDK1.5引入了Scanner类之后,就被人们迅速的摈弃了。
2. Scanner类
Scanner类定义如下:
public final class Scanner implements Iterator<String>, Closeable
Scanner是一个专门进行输入流处理的程序类,利用这个类可以方便处理各种数据类型,同时也可以直接结合正则表达式进行各项处理,在这个类中主要关注以下方法:
// 判断是否有指定类型的数据
public boolean hasNextXxx()
// 取得指定类型的数据
public 数据类型 nextXxx()
// 定义分隔符
public Scanner useDelimiter(Pattern pattern)
// 构造方法
// 注意,它直接接收 InputStream 类,所以我们可以直接传入 System.in
public Scanner(InputStream source)
2.1 Scanner接受键盘数据
使用Scanner接收键盘数据实现如下:
import java.io.IOException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws IOException {
// Scanner
// 比起 BufferedReader 的构造要接收一个 Reader , Scanner的构造只需要接收一个 InputStream ,是在方便了很多
Scanner scanner = new Scanner(System.in);
System.out.print("input:");
if(scanner.hasNext()) {
System.out.print(scanner.next());
}
// 关闭流
scanner.close();
}
}
不要被 next()方法和hasNext()方法的名字迷惑了,它俩本质上就是取得当前输入内容和判断是否当前有输入的内容。而方法名以 “next” 为主体的含义是以当前没有输入为立场:当前还没有输入,所以next个数据就是当前下一刻输入的数据。这点要切记。
2.2 Scanner类接收正则表达式
Scanner类的hasNext()方法的判断依据除了类型,还可以是正则表达式,使用方法如下:
import java.io.IOException;
import java.util.Scanner;
public class Test {
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入生日");
// 输入要遵循的正则表达式
if(scanner.hasNext("\\d{4}-\\d{2}-\\d{2}")) {
System.out.print("生日为:"+scanner.next());
} else {
System.out.print("请输入正确的生日格式!");
}
scanner.close();
}
}
2.3 Scanner类操作文件
Scanner的构造方法是一个InputSream的对象,意味着它可以接受任意文件的字节输入流。使用如下:
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Scanner;
/**
* 测试目录为 E:\IO\demo.txt
*/
public class Test {
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(new FileInputStream(new File("E:\\IO\\demo.txt")));
// 设置分隔符,以该分隔符为界,将输入流分割
scanner.useDelimiter(" ");
while(scanner.hasNext()) {
System.out.println(scanner.next());
}
scanner.close();
}
}
测试文件内容:
运行结果:
从上面的几个例子我们可以看出,Scanner类完美的替代了BufferedReader类,并且完善了InputStream。所以以后关于键盘输出的场景,大可使用Scanner类,一定能满足你的要求。