转换流
读取键盘录入
需求一:读取一个键盘录入的数据,并打印在控制台上。
键盘本身就是一个标准的输入设备,对于java而言,对于这种输入设备都有对应的对象,这些对象在System类中。
默认的输入设备和输出设备都不需要关闭流,这个流会随着系统的出现而出现,随着系统的消失而消失。
public class ReadKey {
public static void main(String[] args) throws IOException {
readKey();
}
// 读取一个键盘录入的数据,并打印在控制台上
public static void readKey() throws IOException {
InputStream in=System.in;
int ch=in.read();//read()是一种阻塞式方法
System.out.println(ch);
int ch1=in.read();//阻塞式方法
System.out.println(ch1);
int ch2=in.read();//阻塞式方法
System.out.println(ch2);
/* A 输入的A
65 输出 A的ASCII码值
13 输出的'\r'的ASCII码值
10 输出的'\n'的ASCII码值
*/
/* 默认的输入设备和输出设备都不需要关闭流
in.close();//不需要关,这个流会随着系统的出现而出现,随着系统的消失而消失
//关了会发生异常:java.io.IOException: Stream closed
InputStream in2=System.in;
int ch3=in2.read();*/
}
}
需求二:获取用户键盘录入的数据,并将数据变成大写显示在控制台上。如果用户输入的是over 结束键盘录入。
思路:
1.因为键盘录入的只读取一个字节,要判断是否是over,需要将读取到的字节拼成字符串
2.那就需要一个容器 StringBuilder
3.在用户回车之前将录入的数据变成字符串判断即可。
public class ReadKey {
public static void main(String[] args) throws IOException {
readKey2();
}
public static void readKey2() throws IOException {
//1.创建容器
StringBuilder sb=new StringBuilder();
//2.获取键盘读取流
InputStream in=System.in;
//3.定义变量记录读取到的字节,并循环获取
int ch=0;
while((ch=in.read())!=-1){
// 在存储之前需要判断是否是换行标记,因为换行标记不存储
if(ch=='\r')
continue;
if(ch=='\n'){
String temp=sb.toString();
if("over".equals(temp))
break;
System.out.println(temp.toUpperCase());
sb.delete(0, sb.length());
}
else
//将读取到的字节存储到StringBuilder中
sb.append((char)ch);
}
}
}
转换流
在读取键盘录入的第二个需求中,我们读取键盘输入的字节,但是需要将判断输入的是否是”over”,即需要将读取到的字节拼成字符串。在需求二里我们自己构建了一个从字节到字符的桥梁。在java中,已经定义好了这样一个桥梁:
转换流
InputStreamReader:字节流到字符流的桥梁。可使用指定的charset将要写入流中的字节解码成字符。它使用的字符集可以由名称指定或显式给定,否则接受平台默认的字符集。(解码)
OutputStreamWriter:字符流到字节流的桥梁。可使用指定的charset将要输出流的字符编码成字节。(编码)
同样的需求用转换流来做:获取用户键盘录入的数据,并将数据变成大写显示在控制台上。如果用户输入的是over 结束键盘录入。
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=System.out;
//转换流
OutputStreamWriter osw=new OutputStreamWriter(out);
//字符流
BufferedWriter bufw=new BufferedWriter(osw);
String line=null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
// System.out.println(line.toUpperCase());
/* osw.write(line.toUpperCase());
osw.flush();*/
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
更加简洁的代码如下:
public class TransStreamDemo{
public static void main(String[] args) throws IOException {
keyToConsole();
}
public static void keyToConsole() throws IOException {
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
字符本身来自于字节,但里面都是由纯文本的数据组成,用字符流操作起来非常方便,用几个需求的实现来感受一下:
package p1.transstream.demo;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
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 TransStreamDemo2 {
public static void main(String[] args) throws IOException {
/*1.需求:将键盘录入的数据写入到一个文件中 demo1
*
* 2.需求:将一个文本文件内容显示在控制台上demo2
*
* 3.需求:将一个文本文件中的内容复制到另一个文件中 demo3
* 只需要改变流的源和目的
* */
// demo1();
// demo2();
demo3();
}
public static void demo3() throws IOException {
BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
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();
}
}
public static void demo2() throws IOException {
BufferedReader bufr=new BufferedReader(new InputStreamReader(new FileInputStream("a.txt")));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
String line=null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
public static void demo1() throws IOException {
BufferedReader bufr=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("a.txt")));
String line=null;
while((line=bufr.readLine())!=null){
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
}
}
流的基本操作规律
IO流的操作规律
流对象太多,开发时不知道用哪个对象合适,这时要寻求流的基本操作规律。
想要知道开发时用到哪些对象。只需要通过四个明确即可:
1.明确源和目的(汇)
源:InputStream、Reader
目的: OutputStream、Writer
2.明确数据是否是纯文本数据
源:
|---是纯文本:Reader
|---否:InputStream
目的:
|---是纯文本:Writer
|---否:OutputStream
到这里,就可以明确需求中具体要使用哪个体系。
3.明确具体的设备
源设备:
|---硬盘:File
|---键盘:System.in
|---内存:数组
|---网络:Socket流
目的设备:
|---硬盘:File
|---控制台:System.out
|---内存:数组
|---网络:Socket流
4.是否需要其他额外功能
1.是否需要高效(缓冲区):
是,就加上buffer
2.是否需要转换(转换流)
规律的体现
需求1:复制一个文本文件。
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:读取键盘录取信息,并写入到一个文件中。
1.明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2.是否是纯文本:是
源:Reader
目的:Writer
3.明确具备设备
源:
键盘:System.in
目的:
硬盘:File
InputStream in=System.in;
FileWriter fw=new FileWriter("b.txt");//这样做可以完成,但是麻烦。将读取的字节数据转成字符串,再由字符流转换为字节流
4.需要额外功能:
转换:
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"));
需求三:将一个文本文件数据显示在控制台上。
1.明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2.是否是纯文本:是
源:Reader
目的:Writer
3.明确具备设备
源:
硬盘:File
目的:
控制台:System.out
FileReader fr=new FileReader("a.txt");
OutputStream out=System.out;
4.是否需要额外功能:
需要,转换:
FileReader fr=new FileReader("a.txt");
OutputStreamWriter osw=new OuputStreamWriter(System.out);
需要,高效:
BufferedReader bufr=new BufferedReader(new FileReader("a.txt"));
BufferedWriter bufw=new BufferedWriter(new OutputStreamWriter(System.out));
需求四:读取键盘录入数据,显示在控制台上。
1.明确源和目的。
源:InputStream Reader
目的:OutputStream Writer
2.是否是纯文本:是
源:Reader
目的:Writer
3.明确具备设备
源:
键盘:System.in
目的:
控制台:System.out
InputStream fr=System.in;
OutputStream out=System.out;
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));
转换流的编码解码
需求五:将一个中文字符串数据按照指定的编码表写入到一个文本文件中。
按照“四个明确”分析:
1.目的 OutputStream Writer
2.是纯文本 Writer
3.设备:硬盘File
FileWriter fw=new FileWriter(“a.txt”);
fw.write(“你好”);
注意:既然需求中已经明确了指定编码表的动作。那就不可以使用FileWriter,因为FileWriter内部是使用默认的本地码表(这里是gbk)。
只能使用其父类。OutputStreamWriter。
OutputStreamWriter接收一个字节输出流对象。既然是操作文件,那么该对象应该是FileOutputStream
OutputStreamWriter osw=new OutStreamWriter(new FileOutputStream("a.txt"),charsetName);
4.需要额外功能
高效:
BufferedWriter bufw=new BufferedWriter(new OutStreamWriter(new FileOutputStream("a.txt"),charsetName));
指定编码表的写出与读入代示例:
public class TransStreamDemo3 {
public static void main(String[] args) throws IOException {
// writeText();
// writeText_2();
// writeText_3();
// readText_1();
readText_2();
}
public static void readText_2() throws IOException {
InputStreamReader isr=new InputStreamReader(new FileInputStream("u8_1.txt"),"UTF-8");
char[] buf=new char[1024];
int len=isr.read(buf);
String str=new String(buf,0,len);
System.out.println(str);
isr.close();
}
public static void readText_1() throws IOException {
FileReader fr=new FileReader("gbk_1.txt");
char[] buf=new char[1024];
int len=fr.read(buf);
String str=new String(buf,0,len);
System.out.println(str);
fr.close();
}
public static void writeText_3() throws IOException {
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("u8_1.txt"),"UTF-8");
osw.write("你好");
osw.close();
}
public static void writeText_2() throws IOException {
OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream("gbk_3.txt"),"GBK");
FileWriter fw=new FileWriter("gbk_1.txt");
/*这两句代码功能是等同的。
FileWriter:其实就是转换流指定了本机默认码表的体现。而且这个转换流的子类对象,可以方便操作文本文件。
简单说:操作文本的字节流+本机默认的编码表
这是按照默认码表来操作文件的便捷类
如果操作文本文件需要明确具体的编码,必须用转换流,不能再用FileWriter。*/
osw.write("你好");
osw.close();
}
public static void writeText() throws IOException {
FileWriter fw=new FileWriter("gbk_1.txt");
fw.write("你好");
fw.close();
}