文章目录
1 转换流
把字节流转成字符流,再用字符流的方法,处理字节
1.1 InputStreamReader
InputStreamReader是字节流通向字符流的桥梁;它使用指定的 charset 读取字节并将其 解码为字符。
它使用的字符集可以由名称指定或显式给定,或接受平台默认的字符集。
每次调用 InputStreamReader中的一个 read()方法 都会导致从底层输入流读取一个或多个字节。
要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。
为了达到最高效率,可以考虑在 BufferedReader内 包装 InputStreamReader。如:
BufferedReader in = new BufferedReader( new InputStreamReader(System.in));
字符流的由来就是 字节流+编码表,字节流+编码表 组成的对象 就是 转换流
1.2 OutputStreamWriter
读和写正好是相反的,读—读的都是字符数据 — 字节变字符。写 — 写的都是字节数据 — 字符变字节
OutputStreamWriter 的 直接子类 — FileWriter
OutputStreamWriter 已经把字符转换为了字节, FileWriter就不用转换了, 直接拿过来用就可以了
代码实例:
将键盘录入的数据写入到一个文件中
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
String line = null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
将一个文本文件内容显示在控制台上
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt") ) );
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out);
将一个文件文件中的内容复制到的另一个文件中
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("a.txt") ) );
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("b.txt")));
1.3 转换流的使用场景
什么时候使用转换流
1 源或者目的对应的设备是字节流,但是操作的却是文本数据,可以使用转换作为桥梁,提高对文本操作的便捷
2 一旦操作文本涉及到具体的指定编码表时,必须使用转换流码表是固定写死的,必须使用转换流来做
将一个中文字符串数据按照指定的编码表写入到一个文本文件中
分析:
FileWriter fw = new FileWriter("a.txt");
fw.write("你好");
注意:既然需求中已经明确了指定编码表的动作,那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表,只能使用其父类。OutputStreamWriter
OutputStreamWriter接收一个字节输出流对象,既然是操作文件,那么该对象应该是FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),charsetName);
需要高效吗?
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(“a.txt”),charsetName));转换流
OuputStreamWriter
可以指定编码表
public static void writeText() throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk_1.txt"),"utf-8");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
说明:
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("gbk_3.txt"),"GBK"); OutputStreamWriter osw = new >OutputStreamWriter(new FileOutputStream("gbk_3.txt")); FileWriter fw = new FileWriter("gbk_3.txt");
这三句代码的功能是等同的。 使用的都是默认的码表
FileWriter:其实就是转换流指定了本机默认码表的体现
只要看到一堆乱七八糟的中文,一定是用 GBK解码 解出来的,只有GBK能解码中文
InputStreamReader isr = new InputStreamReader(new FileInputStream("u8_1.txt"),"gbk");
// 乱码
只能是相同的编码,相同的解码用GBK编码,用GBK解码
用 utf-8编码,用 utf-8 解码
用GBK编码的文件,用 utf-8来解码。出来的是 ??(你好)
2 IO流 操作规律
流对象太多,开发时不知道用哪个对象合适,弄清楚 IO流操作规律,可以很好的掌握 IO流的使用
四个明确
1 明确源和目的(汇)源:
InputStream Reader
汇:OutputStream Writer
2 明确数据是否是纯文本数据
源是纯文本数据 :
Reader
不是InputStream
目的是纯文本数据:Writer
不是OutputStream
3 明确具体设备
源设备: 硬盘
File
键盘System.in
内存数组
网络Socket流
目的设备:硬盘File
键盘System.out
内存数组
网络Socket流
4 是否需要其他额外功能
1 是否需要高效(缓冲区) — 是,就加上 Buffer
2 是否需要转换 — 是,转换流InputStreamReader OutputStreamWriter
代码实例
2.1 演示键盘录入,并打印在控制台上
读取一个键盘录入的数据,并打印在控制台上
private static void readOneByte() throws IOException {
InputStream in = System.in;
int ch = in.read(); // 阻塞式方法,有数据就读,没有数据就等,所以是阻塞式方法
System.out.println(ch);
int ch1 = in.read();//阻塞式方法。
System.out.println(ch1);
int ch2 = in.read();//阻塞式方法。
System.out.println(ch2);
/*
* 其他对象,关了之后,接着 new一个,还可以读,但是标准类不行
* System.in --- 从系统获取的流对象就一个,关了就没有了,
* 所以不用关,它会随着系统的消失而消失
*/
// in.close(); // 为什么不关流 因为关了之后,就没办法再读了
}
输出结果:
a
97
13
10
分析:
上面的代码,只能读3个数据,因为就写了读3个字节的方法,为什么会出现 13 ,10?每读取一个字符,都会输出 13 10 — 回车符 \r\n的ASCII码 a 对应 97
想不断的读取键盘录入的数据,应该怎么做,— 循环int ch = 0; while ( (ch=in.read()) !=-1 ){ System.out.println(ch); }
改进:
要求
获取用户键盘录入的数据
并将数据变成大写显示在控制台上
如果用户输入的是over,结束键盘录入结束标记,是用户自己定义的,而不是 按快捷键等强行结束
思路
键盘录入一次只读取一个字节 — 如果是中文,需要读两次1,因为键盘录入只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串。
2 需要一个容器。StringBuilder
3 在用户回车之前将录入的数据变成字符串判断即可
private static void readBytesEndWithOver() throws IOException {
// InputStream in = System.in; // 键盘录入有一个弊端,一次只能读取一个字节
StringBuilder sb = new StringBuilder(); // 1 创建容器
InputStream in = System.in; // 2 获取键盘 读取流
int ch = 0; // 定义变量,记录读取到的字节,并循环获取
while((ch=in.read())!=-1){
// 在存储之前,需要判断是否是换行标记,因为换行标记不存储
if(ch=='\r'){
continue;
}
if(ch=='\n'){ // 如果是 \n,说明一行结束了
String temp = sb.toString();
if("over".equals(temp))
break;
System.out.println(temp.toUpperCase());
//如果不加这一行,再次输入时,会把上次和以前所有的输入的内容,都显示出来
sb.delete(0,sb.length());
}
else
sb.append((char)ch);//将读取到的字节存储到StringBuilder中
}
}
输出结果:
asd
ASD
vbn
VBN
over
2.2 复制一个文本文件
分析
1 明确源和目的:源:InputStream Reader
目的:OutputStream Writer
2 是否是纯文本 :是— 源Reader
汇Writer
3 明确具体设备:源:硬盘File
目的:硬盘File
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
流对象一旦确定,剩下的就是读写操作4 需要额外功能吗:需要,需要高效
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
2.3 读取键盘录入的信息,并写入到一个文件中
分析
1 明确源和目的:源:InputStream Reader
目的:OutputStream Writer
2 是否是纯文本 :是— 源Reader
汇Writer
3 明确具体设备:源:键盘System.in
目的:硬盘File
InputStream in = System.in;
FileWriter fw = new FileWriter("b.txt");
这样做可以完成,但是麻烦。将读取的字节数据转成字符串。再由字符流操作4 需要额外功能吗:需要,需要转换
将字节流转成字符流。因为明确的源是Reader,这样操作文本数据做便捷。
所以要将已有的字节流转成字符流。使用字节–>字符 —InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
FileWriter fw = new FileWriter("b.txt");
还需要功能吗?需要 — 高效
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new FileWriter("b.txt"));
2.4 将一个文本文件数据 显示在控制台上
分析
1 明确源和目的:源:InputStream Reader
目的:OutputStream Writer
2 是否是纯文本 :是— 源Reader
汇Writer
3 明确具体设备:源:硬盘File
目的:控制台System.out
FileReader fr = new FileReader("a.txt");
OutputStream out = System.out;//PrintStream
流对象一旦确定,剩下的就是读写操作4 需要额外功能吗:需要,转换
FileReader fr= new FileReader("a.txt");
OutputStreamWriter osw = new OutputStreamWriter(System.out);
需要,高效
BufferedReader bufr = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
2.5 读取键盘录入的数据,显示在控制台
分析
1 明确源和目的:源:InputStream Reader
目的:OutputStream Writer
2 是否是纯文本 :是— 源Reader
汇Writer
3 明确具体设备:源:键盘System.in
目的:控制台System.out
InputStream in = System.in;
OutputStream out = System.out;//PrintStream
流对象一旦确定,剩下的就是读写操作4 需要额外功能吗:需要,转换。因为都是字节流,但是操作的却是文本数据。所以使用字符流操作起来更为便捷。
InputStreamReader isr = new InputStreamReader(System.in);
OutputStreamWriter osw = new OutputStreamWriter(System.out);
需要,高效
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));