至此,我们已经介绍完了字符流和字节流。但是,我们会注意到这样一个问题,程序中所需要的数据,都是事先已经定义好的,那么程序能否处理,由我们输入的数据呢?即读取键盘的数据。答案是肯定的,那么又该如何读取呢,是否有相应的对象?
请看下面示例:系统为我们提供了 System.in 来进行 数据的输入。
接下里要做的就是,读取由键盘输入的数据。
import java.io.IOException;
import java.io.InputStream;
public class ReadKeyTest {
public static void main(String[] args) throws IOException {
/*
*读取键盘System.in
*/
readKey();
}
//读取键盘录入。
public static void readKey() throws IOException{
//获取到读取键盘录入的流对象。类型是InputStream
InputStream in = System.in;
//用流读取数据。如果没有数据录入,那么控制台会一直等待输入。read方法就是一个阻塞式的方式。
for(int i = 0 ; i < 5 ; i++){
int ch = in.read();
System.out.println(ch + " i = " + i);
}
//注意:系统中获取的流对象都是唯一的,如果将其关闭,就不再使用了。
//想要再使用只有重新再次运行这个程序才可以。
//所以一般情况下,从System获取到的流对象,一般不需要关闭。随着程序的停止而结束。
}
}
在这个示例中,我们应当注意:
1. System.in 可以获取用于处理键盘录入的流对象,它的类型是 InputStream。
2. read() 方法是阻塞式方法即—— 当用流读取数据时。如果没有数据录入,那么控制台会一直等待输入。
3. 从System获取到的流对象,不需要关闭。
接下来,我们要做的Demo是,将从键盘录入的数据转成大写打印在控制台:
该如何做呢?解决问题是,必须先得有思路,那么思路是什么呢?
思路:
1,通过键盘录入读取字节数据。
2,将这些读到的字节数据进行存储以变成字符串。
3,对这个字符串进行判断。如果不是over就将其转成大写打印。如果是over就结束。
import java.io.IOException;
import java.io.InputStream;
public class ReadKeyTest2 {
public static void main(String[] args) throws IOException {
readKey2();
}
public static void readKey2() throws IOException {
//1,获取键盘录入流对象。
InputStream in = System.in;
//2,定义一个容器用于存储读取到的字节。
StringBuilder sb = new StringBuilder();
//3,循环读取键盘。
int ch = 0;
while((ch=in.read())!=-1){
//需要对读取到的字节进行判断。
//如果是/r 或者 /n,不存储,并视为一次录入内容结束符。对之前的录入数据进行判断。
if(ch=='\r')
continue;
if(ch=='\n'){
String s = sb.toString();
if("over".equals(s)){//记住:如果要使用键盘录入,一定要自定义结束标记。
break;
}
else{
System.out.println(s.toUpperCase());
//清空缓冲区。
sb.delete(0, sb.length());
}
}
else
sb.append((char)ch);
}
}
}
在这个示例中,我们应当注意的是:
1. 玩儿键盘录入,必须定义结束标记 ,这个案例中 为 “over”
2. 注意清空缓冲区,否则打印出来的数据,将会累积,越来越长。
既然键盘录入转成大写输出,并判断over结束的程序中。使用了到对字节数据的存储,并对回车符进行判断。发现这个功能和readLine方法一致。
既然readLine方法已经封装了这些动作,直接使用readLine不就行了吗? 但是,我们又发现,readLine()方法是字符流BufferedReader 对象中的方法。而键盘录入是字节流。能不能将这个字节读取流转成字符流呢?因为BufferedReader只能对字符流进行装饰。 这就需要讲字节里转换为 字符流,以便使用字符流中的数据。接下来,我们将学习【转换流】,当然也是 IO体系中一个非常重要的对象:他是字节流和字符流转化的桥梁。
InputStreamReader—— 字节流通向 字符流的桥梁。
OutputStreamWriter—— 字符流通向字节流的桥梁。
可以这样理解:
将看不懂的字节数据,变为看的懂的字符数据——即:读取,用InputStreamReader
将能看懂的字符数据变为看不懂懂字节数据+即:写,用OutputStreamWriter。
因此,我们用转换流来对上述例题再度理解:
读取键盘录入的数据,将这些数据转成大写打印在屏幕上,如果录入的是 over, 程序结束。
思路:
1. 获取键盘录入,数据源;
2. 为了处理文字数据方便,将字节数据转成字符数据,这个功能在转换流中
3. 将数据源与 转换流关联
4. 为了提高效率,使用缓冲区
5. 明确目的:打印到显示器上。
6. 因为要打印到显示器上的数据都是文字数据所以必须将这些文字转成字节数据。具备这个功能的对象是OutputStreamWriter。
7. 为了提高写入效率。从缓冲区
8. 进行频繁读写操作。
9. 因为是从System获取的流可以不关闭,随着系统的的结束而结束。
代码如下:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
public class TransStreamDemo {
public static void main(String[] args) throws IOException {
//键盘录入。字节读取流。
InputStream in = System.in;
//创建一个转换流。是一个字符流,在构造时,将字节流作为参数传入构造函数。,
InputStreamReader isr = new InputStreamReader(in);
//为了高效,创建缓冲区
BufferedReader bufr = new BufferedReader(isr);
//创建目的地
OutputStream out = new FileOutputStream("tempfile\\out.txt");
//创建转换流。是一个字节流,将字符流转换为字节流
OutputStreamWriter osw = new OutputStreamWriter(out);
//为了高效,创建缓冲区
BufferedWriter bufw = new BufferedWriter(osw);
//频繁的读写操作
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
简写形式如下:
至此,我们已经学过了好多的处理IO的对象,对于这么多的对象,他们怎么用,什么时候用,接下来,我们有必要将其 做一个系统的总结。