字符流回顾 字符流:字节流+编码表
InputStreamReader是从字节流到字符流的桥梁:它读取字节,并使用指定的charset(编码表)将其解码为字符。它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台的默认字符集。说白了它就是用来将字符流和字节流之间做了一个转换而已。
OutputStreamWriter是从字符流到字节流的桥梁:使用指定的charset(编码表)将写入的字符编码为字节。它使用的字符集可以由名称指定,也可以被明确指定,或者可以接受平台默认的字符集。说白了它就是用来将字符和字节这两者之间做了个转换。
下图的解释:
首先我在本地有一个文件,现在我要用FileReader去读取它。因为FileReader它底层是字节流+编码表的形式,所以实际上还是用字节流去读取的,所以一开始是字节流,然后呢通过中间的InputStreamReader它会把字节流转换成FileReader,这时候才会到内存当中,而它中间转换的格式会按照我们指定的编码表来进行转换。当它要往外写时就会用到FileWrite往外写,但是在底层它也会通过OutputStreamWriter转换成字节流再写到本地文件中去。
右边这个OutputStreamWriter就是用来把字符流转换成字节流,
而左边那个InputStreamReader就是用来将字节流转换为字符流。
转换流的使用场景
在JDK11之前,转换流可以用作指定编码读写,在DJK11以后,一般不会直接去操作转换流了。
下面这串代码为什么会出现乱码?
public class ConvertedDemo1 {
public static void main(String[] args) throws IOException {
//a.txt内部存储着五个汉字,连起来是:冬马是小三
/*
这个方法直接读取会产生乱码
因为文件是GBK码表
而idea默认是UTF-8编码格式
所以两者不一致,导致乱码
*/
FileReader fr = new FileReader("D:a.txt");
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
fr.close();
}
}
因为记事本默认码表是ANSI,而idea默认码表是UTF-8,这两者之间的码表不一致,所以有冲突,最后就会输出乱码。想要得到正确输出的方式是改变记事本或idea的默认编码。(一般改变记事本的默认编码)
如何用代码解决此问题?
使用转换流解决,第一个参数传递一个字节流,第二个参数传递字符集名称(charsetName)(可省略)。
public class ConvertedDemo1 {
public static void main(String[] args) throws IOException {
//a.txt内部存储着五个汉字,连起来是:冬马是小三
/**
* 如何解决乱码现象?
* 文件是什么码表,那么咱们就必须使用什么码表去读取。
* 那么我们就要指定使用GBK码表去读取文件
*/
// 第一个参数写字节输入流,第二个参数写编码方式
InputStreamReader isr = new InputStreamReader(new FileInputStream("D:a.txt"),"GBK");
int ch;
while((ch = isr.read()) != -1){
System.out.print((char)ch);
}
isr.close();
}
}
向外写
public class ConvertedDemo1 {
public static void main(String[] args) throws IOException
// 第一个参数写字节输出流,第二个参数写编码方式
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("D:b.txt"),"utf-8");
osw.write("她也是我的心上人");
osw.close();
}
}
问:1:为什么向外写时指定了编码格式为UTF-8,但用记事本打开时却不显示乱码?
因为window系统会自动用UTF-8去读取。
问题2:打开记事本将它用ANSI格式打开会报错了?
答:不会,因为记事本这个软件会自动使用正确的格式将它打开。(这跟代码无关)
JDK11可以不用转换流而使用FileReader这个类,下面这段代码应该能用,但我没测试过。。。
public class ConvertedDemo1 {
public static void main(String[] args) throws IOException {
//a.txt内部存储着五个汉字,连起来是:冬马是小三
FileReader fr = new FileReader("D:a.txt", Charset.forName("gbk"));
int ch;
while((ch = fr.read()) != -1){
System.out.print((char)ch);
}
fr.close();
}
}