「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战」
思考:既然字节流可以操作所有文件,那么为什么还要学习字符流?
- 如果利用字节流,把文本文件中的中文,读取到内存中,有可能出现乱码?
- 如果利用字节流,把中文写到文本文件中,也有可能出现乱码。
编码表:
基础知识:
-
计算机中存储的信息都是用二进制数来表示的。
-
按照某种规则,将字符变成二进制,再存储到计算机中,称为编码。
-
按照同样的规则,将存储在计算机中的二进制数,解析显示出来,称为编码。
-
编码和解码的方式必须一致,否则会导致乱码。
简单理解: 存储一个字符a,首先需在码表中查到对应的数字是97,然后转换成二进制进行存储。 读取的时候,先把二进制解析出来,再转成97,通过97查找到对应的字符是a。
编码表:
ASCII 字符集:
ASCII: 包括了数字,大小写字符和一些常见的标点符号。
注意:ASCII 码表中 是没有中文的。
GBK: window系统默认的码表,兼容ASCII码表,也包含了 21003个汉字,并支持整体汉字以及部分日韩文字。
注意:GBK 是中国的码表,一个中文以两个字节的形式存储。但不包含世界上所有国家的文字。
编码表:
Unicode码表:
由国际组织ISO制定,是统一的万国码,计算机科学领域里的一项业界标准,容纳世界上大多数国家的所有常见文字和符号。
但是因为表示的字符太多,所以Unicode 码表中的数字不是直接以二进制的形式存储到计算机的。
会先通过UTF-7, UTF-7.5, UTF-8, UTF-16, 以及UTF-32进行编码,再存储到计算机,其中最为常见的就是UTF-8.
注意: Unicode 是万国码, 以 UTF-8 编码后一个中文以三个字节的形式存储。
字符串中的编码解码问题
public class CharStreamDemo2 {
public static void main(String[] args) throws UnsupportedEncodingException {
String s = "你好啊";
byte[] bytes = s.getBytes();
System.out.println(Arrays.toString(bytes));
byte[] bytes2 = s.getBytes("UTF-8");
System.out.println(Arrays.toString(bytes2));
byte[] bytes3 = s.getBytes("GBK");
System.out.println(Arrays.toString(bytes3));
byte[] bytes4 = {-28, -67, -96, -27, -91, -67, -27, -107, -118};
byte[] bytes5 = {-60, -29, -70, -61, -80, -95};
// 默认utf-8解码
String s1 = new String(bytes4);
System.out.println(s1);
// gbk 解码
String s2 = new String(bytes5,"gbk");
System.out.println(s2);
}
}
为什么字节流读取文本文件,可能出现乱码?
因为字节流一次读一个字节,而不管GBK还是UTF-8 一个中文都是多个字节,用字节流每次只能读其中的一部分,所以就会出现乱码问题。
public class CharStreamDemo3 {
public static void main(String[] args) throws IOException {
// 创建字符输出流的对象
FileWriter fw = new FileWriter("a.txt");
// 写出数据
// 写一个字符
// fw.write(97);
// fw.write(98);
// fw.write(99);
// 写出一个字符数组
// char [] chars = {97,98,99,100};
// fw.write(chars);
//
//写出字符数组的一部分
// char [] chars = {97,98,99,100};
// fw.write(chars,1,3);
// 写一个字符串
// String line = "kjfsdkdsf";
// fw.write(line);
// 写一个字符串的一部分
String line = "ddsds";
fw.write(line,0,2);
// 释放资源
fw.close();
}
}