举例:
我们之前在读取文件的时候,文件中都是用英文举例,
如果文件内有中文,读取会发生什么
举例:
进行读取,
//创建字节输入流对象
FileInputStream fis=new FileInputStream("..\\ioDemo\\a.txt");
//循环读取,(无参read一次读取一个字节)
int len;//表示每次读取到的ascii码
while((len=fis.read())!=-1){
System.out.print((char) len);
}
//释放资源
fis.close();
可以发现,英文正常读取,而中文部分乱码。
***若此时在Hello这五个字符后再添加一个任意字符字符,
也就是6个字母+2个中文
并且我手动采取一次读取三个字节的解码规则
此时再读取还会报错吗?
public class t {
public static void main(String[] args) throws IOException {
//创建字节输入流对象
FileInputStream fis = new FileInputStream("..\\ioDemo\\a.txt");
//循环读取,
byte[] bytes = new byte[3];//(一次读取三个字节)
int len;
while ((len = fis.read(bytes)) != -1) {
String str = new String(bytes, 0, len);//获取每一次读取到的元素
System.out.println(str);//打印
}
//释放资源
fis.close();
}
}
由此可以,
我当前系统的默认编码规则是:一个英文字母占一个字节、一个中文占三个字节。
为了了解为什么乱码?,如何才能不乱码?
我们就要学习,计算机存储规则以及字符集。
计算机存储规则:
在计算机中,任意数据都是以二进制的形式存储的,如00111000,
一串二进制数就代表着某个数据
字节是计算机最小的存储单元。
字符集
一、字符集的介绍
字符集就像是一本字典,当电脑想要知道某串二进制数代表的真实数据,就需要查询该串二进制数在字典上所表示的数据,(字典上已经记录了该二进制数和真实数据的对应关系)。
而乱码出现的原因 其实就是查错了字典,如,汉字字典用拼音表示,牛津字典用音标表示,当我们要查某个汉字时,拿牛津字典当然查到的不是正确的数据
例如:拼音tan表示的中文有很多,就拿“弹”来说,而在英文中tan的含义是“棕褐色的”
这就是不同字符集之间的差异;字符集是计算机二进制数据的字典。
字符集分类:
Ascii:
ASCII码是一种基于英文字符的编码系统,主要用于计算机通信。**标准ASCII码使用7个二进制位(每个字符占用一个位)来表示128个不同的字符。**这是因为2的7次方等于128,所以标准ASCII码能够表示的最大字符数量是128个。123
除此之外,还有一种称为扩展ASCII码的编码方式,它使用8个二进制位来表示额外的128个字符。这样,扩展ASCII码总共能表示256个字符,这包括了更多的符号类型,如拉丁字母、数字、标点符号以及一些特殊用途的控制字符。
只有英文的编码规则,一个英文占一个字节,前面补0,补齐八位
如:
一共才128个字符,也就是只要一个字节即可表示完,28 =256
GBK
简体中文版WINDOWS默认使用GBK字符集:系统显示:ANSI
有中文、英文的编码规则:
- 英文编码规则(完全兼容ASCII):一个字节,不足8位,前面补0,如:
- 中文编码规则:每个汉字两个字节存储、高位字节二进制一定以1开头,转成十进制后是一个负数
- 为什么一定要是1开头呢?
- 为了和英文区分,而Ascii码英文以及字符一共才128个,最高位二进制一定是0
- 练习:
规则:
Unicode(完全兼容ASCII)
国际标准字符集,它将世界各种语言的每个字符定义为唯一的编码,以满足跨语言、跨平台的文本信息转换。
有中文、英文的编码规则(这里指的是Unicode的 UTF-8编码规则)
UTF-8的编码规则(二进制):
用1-4个字节保存,
英文:1个字节(最高位是0),转成二进制是正数
中文:三个字节(最高位是1),第一个字节转成十进制是负数
”汉“ 查询Unicode是27721转换成二进制 01101100 01001001 UTF-8编码变成:11100110 10110001 10001001
注意:UTF-8不是一个字符集,它是Unicode字符集的一种编码方式!
练习:
了解完了字符集,应该也知道了乱码的原因了,
那么如何才能不乱码?
- 不要用字节流读取文本文件(一次只会读取一个字节,不管文本使用的是GBK还是Unicode编码规则,都会导致中文二进制部分的读取缺失)
- 编码、解码时使用同一个码表,同一个编码方式
编码就是把真实数据变成一串二进制数,
解码就是把这一串二进制数,使用一定的规则得到真实数据
编码方法的返回值是一个字节数组
解码方法的返回值是一个字符串
编码,解码使用同一个编码方式:
public class Test {
public static void main(String[] args) throws UnsupportedEncodingException {
//文本
String str="Hello世界";
//编码
byte[] bytes1 = str.getBytes();//使用默认的编码方式UTF-8(我的系统),一个英文一个字节,一个中文三个字节
System.out.println(Arrays.toString(bytes1));//[72, 101, 108, 108, 111, -28, -72, -106, -25, -107, -116]
byte[] bytes2 = str.getBytes("GBK");//使用GBK编码方法,一个英文一个字节,一个中文两个字节
System.out.println(Arrays.toString(bytes2));//[72, 101, 108, 108, 111, -54, -64, -67, -25]
//解码:
String str2=new String(bytes1);//对bytes1使用默认的解码方式(UTF-8)
System.out.println(str2);//Hello世界-------无误
String str3=new String(bytes1,"GBK");//对bytes2使用GBK解码方法
System.out.println(str3);//Hello涓栫晫---------使用UTF-8编码,GBK解码,直接乱码,因为中文的存储规则不同
}
}