参考大神链接:http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/
关于ASCII,GB2312,GBK,单字节编码,多字节字符集,字节编码,字符集,代码页,码表等概念,参见这篇文章:
Situation&Complication:
编码问题一直困扰着开发人员,尤其在 Java 中更加明显,因为 Java 是跨平台语言,不同平台之间编码之间的切换较多。如何理解内码(internal encoding)和外码(external encoding),如何理解“在Java中字符只以一种形式存在,那就是unicode” 这句话呢?
SubJect
本文将以JavaIO中存在的编码为例,从内存角度对Java编码进行解析
1. 使用FileReader读取GBK文件(中文操作系统下默认编码方式是GBK)
(1)代码如下(a.txt是GBK编码的文本文件)
public static void main(String[] args)throws IOException {
FileReader fr = new FileReader("C:\\a.txt");
char[] chs = new char[16];
int length = 0;
while((length = fr.read(chs))!=-1){
System.out.print(String.valueOf(chs,0,length));
}
}
(2)内存图解(以I am 君山这句话为例)
(3)工作原理
在将文本从外部文件读入内存中时,存储到内存中byte[]中。在JVM中、在内存中、在代码里声明的每一个char、String类型的变量中字符以unicode格式存在。
如果你在eclipse将java文件properties的默认编码方式有GBK改为UTF-8,就会乱码。因为你使用UTF-8来解码GBK编码的字节流。具体原理分析见2.
2. 使用FileReader读取UTF-8文件
(1) 代码如下(a.txt是UTF-8编码的文本文件)
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("C:\\a.txt");
char[] chs = new char[16];
int length = 0;
while((length = fr.read(chs))!=-1){
System.out.print(String.valueOf(chs,0,length));
}
}
(2)内存图解(以I am 君山这句话为例)
(3) 工作原理
结果是 I am 鍚涘北
造成乱码的原因就是因为使用了错误的字符编码去解码字节流。字符文本是UTF-8编码的字节流,用unicode字符集,但是采用默认的GBK的字符编码,即用GBK来解码UTF-8编码的字节流。
实际上在内存中存储的用unicode编码的结果就是错的。
有两种解决方案:
1. 将系统的默认编码方式改为UTF-8,这样就使用正确的字符编码来解码了。
2. 采用下面3的方式,使用转换流,指定解码的码表。无论你的默认编码方式是什么,都可以获得正确的输出。因为在内存中你存了正确的unicode编码的字节序列。
3. 使用InputStreamReader读取UTF-8文件
(1) 代码如下(a.txt是UTF-8编码的文本文件)
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("C:\\a.txt"), "UTF-8"));
String line = null;
while ((line=br.readLine())!=null) {
System.out.println(line);
}
br.close();
}
(2)内存图解(以I am 君山这句话为例)
(3) 工作原理
在将文本从外部文件读入内存中时,存储到内存中byte[]中。在JVM中、在内存中、在代码里声明的每一个char、String类型的变量中字符以unicode格式存在。与第二种情况不同的是,指定了字符编码的码表是UTF-8,与文本文件编码的方式是相同的,从而保证在内存中存储的unicode编码的字节是正确的。
总结:最终就可以这样理解
当保存字符的时候,就是字符String -> 通过unicode字符集映射 -> utf-8编码格式编码 以二进制存储在磁盘中字节
当获取字符的时候,就是 存储在磁盘中的二进制字节 -> utf-8格式解码 -> 通过unicode字符集映射 -> 字符String