最近工作中遇到一个编码的问题,在这记录一下我的思考过程,供大家参考。
先来一段测试代码,看完结果之后再说一下我的思考和理解:
public static void main(String[] args) {
File tmpFile = new File("test.txt");
OutputStreamWriter osw = null;
InputStreamReader isr = null;
try {
Boolean result = tmpFile.createNewFile();
FileOutputStream fos = new FileOutputStream(tmpFile);
osw = new OutputStreamWriter(fos, "UTF-8");
osw.write("helloword,中国深圳,龙岗区");
osw.flush();
FileInputStream fis = new FileInputStream(tmpFile);
isr = new InputStreamReader(fis, "GBK");
StringBuffer sb = new StringBuffer();
while (isr.ready()) {
sb.append((char) isr.read());
}
System.out.println("-----------------------------------------------------------------------");
System.out.println(sb.toString());
System.out.println(new String(sb.toString().getBytes("GBK"),"UTF-8"));
System.out.println("-----------------------------------------------------------------------");
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(osw != null) osw.close();
if(isr != null) isr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
执行结果:
-----------------------------------------------------------------------
helloword,涓浗娣卞湷,榫欏矖鍖�
helloword,中国深圳,龙岗�?
-----------------------------------------------------------------------
我故意用GBK去解析UTF-8写入的字符串,读出来的字符串肯定会乱码,是的,这个很好理解,关键说第二条打印的数据: 我将读出来的UTF-8字符串再转成GBK的二进制,然后再装成UTF-8的字符串,发现和我最初的字符串并不相同! 其实,这是因为转成"helloword,涓浗娣卞湷,榫欏矖鍖�"的GBK字符串时,数据以及在翻译的过程中被破坏了,“�”其实就是由于在GBK中找不到对应的含义的字符才生成的一个通用字符,你想想,此时再反过来操作一遍,肯定是得不到原来的字符串了。当然这种情况也不是一定会发生,这个要看具体的两个编码。
关于编码的认知
所有在计算机中展示出来的数据都是计算机通过固定的编码,将二进制数据转换成人类能够看的懂的字符,在人与计算机交互的过程中,编码(Unicode,UTF-8,GBK等)就相当于一个中介,准确点说应该是翻译。
关于编码转换
在JVM中,字符串String是没有编码的概念的,因为JVM是统一使用的Unicode进行String的计算和存储的,这样才能保证相同的字符串计算出来的二进制是相同的; 所以,在java中,相同的字符串,要实现A到B编码的转换,过程是这样的:二进制先按照A编码转换成String(unicode),然后String再按照B编码转换成二进制。 这里其实就涉及Java中两个不得不说的API: 1、String.getBytes(“GBK”) :将String转换成指定编码的二进制数组。 2、new String(二进制数组,“GBK”) :将二进制数组按照指定的编码解析成字符串。
结论
1、对于某一个二进制数组[]byte,如果不知道它的原生编码,计算机是没办法正确解析它的,因为计算机不知道要将它解析成什么样子人类才看得懂。 2、对于某一个二进制数组[]byte,如果不知道它的原生编码,是没办法转换成某一种其他的固定编码的(因为翻译出来的String不确定是否正确,与第一个结论相同)。 3、对于某一个二进制数组[]byte,如果知道它的原生编码为A,用非原生编码B对其进行解析之后得到的String C是会存在数据被破坏的风险的,也就是说,此时的字符串C如果再用B编码生成二进制[]byte,然后通过A转换成字符串D,此时,C不一定等于D,也就是说,这个过程不一定可逆,从最上面的代码可以看出。 4、所以,最关键的一条结论来了:为了保证双方数据一致性,双方在读和写的过程中使用的编码一定要一致,用不相同的编码翻译过的数据就不能逆向使用。
|