采用readLine方法对txt文本读取中文字符显示乱码,尽管很快找到解决方案,但疑惑反而更多。
1.问题
RandomAccessFile ran=new RandomAccessFile("D:/test.txt","r");
System.out.println(ran.readLine());
当直接用readLine方法对txt文件里的中文字符读取时,显示出来的是乱码。
2.解决方案
经过查找,网上的解决方案是
System.out.println(new String(ran.readLine().getBytes("iso-8859-1"),"gbk"));
2.1.简单介绍下字符集(可跳过)
1、 ISO-8859-1
又称为西欧语言,在ascll码的基础上增加了96个字符和符号,单字节编码,无法表示中文。
2、GB2312/GBK/GB18030
GB2312:我国国家标准简体中文字符集,双字节编码。
GBK:汉字内码扩展规范,不属于国家标准,但囊括范围更广,兼容GB2312。
GB18030:国家标准,在GBK基础上再增加内容。(好像少见)
3、Unicode
计算机科学领域的业界标准,对世界上大部分的文字系统进行了整理、编码。
4、utf-8/utf-16
都是一种针对Unicode的可变长度字符编码。区别在于:
utf-8:对字符采用1到4字节编码。中文是3个字节。
utf-16:对大部分字符采用2字节编码,极少部分采用4字节编码。
2.2.接着解决方案
System.out.println(new String(ran.readLine().getBytes("iso-8859-1"),"gbk"));
解决方案的意思是:
(提下编码解码的概念:编码:把字符转换成字节。解码:把字节转换成字符。)
将readLine读取出来的字符串通过getBytes方法按iso-8859-1编码成字节数组,然后再将字节数组按gbk解码,最后转换成字符串输出。
[2022.9.16更新]删除一些多余的解释,主要的原因在readLine()源码里。
2.3.readLine()源码
public final String readLine() throws IOException {
StringBuffer input = new StringBuffer();
int c = -1;
boolean eol = false;
while (!eol) {
switch (c = read()) { //read():每次读取一个字节
case -1:
case '\n':
eol = true;
break;
case '\r':
eol = true;
long cur = getFilePointer();
if ((read()) != '\n') {
seek(cur);
}
break;
default:
// 重点就这一句
input.append((char)c);
break;
}
}
if ((c == -1) && (input.length() == 0)) {
return null;
}
return input.toString();
}
[2022.9.16更新]重写了对源码的解析,以前研究的不够透彻。
- readLine方法通过read()方法读取文本文件里存储的字节。
- 然后将int型的字节数据转换成char型,重点在这里。
char类型用2个字节的Unicode值表示一个字符,读取到的GBK编码单字节被添加了一个全零的字节组成了Unicode值。
而iso-8859-1是单字节编码,对这个Unicode值进行iso-8859-1编码将会去掉前面补充的零,得到原来GBK编码的字节,这时再用GBK解码即可得到原来的字符。
举个例子——
- "你"字对应的GBK编码是0xC4E3(0x表示十六进制)
- read()方法读取到两个int类型的字节0xC4和0xE3,转变成char型:0x00C4,0x00E3
- 如果直接输出,编译器会直接查找/计算0x00C4这个Unicode值对应的字符,很显然会输出乱码。
- 采用iso-8859-1编码后:0xC4,0xE3
- 采用GBK解码成Unicode值:0x4F60,为什么不是解码成字符?因为char或String类型存储的就是Unicode值,经过查找或计算就能得到相应的字符。
- 如果不采用iso-8859-1编码直接GBK解码会怎么样?编译器将会对0x00C4,0x00E3进行GBK解码,因为GBK编码解码是两个字节对应一个字符的,所以会得到两个字符,这种情况也会导致乱码。
因为在写另一份更加详细的java字节流读取博客,所以对这篇博客的修改很粗糙,可能你看完有点点感觉但好像又没完全弄懂,可以看下这篇——Java字节流读取中文文本编码解码详解