从内存角度解析Java字符编码

参考大神链接:http://www.ibm.com/developerworks/cn/java/j-lo-chinesecoding/

 

关于ASCII,GB2312,GBK,单字节编码,多字节字符集,字节编码,字符集,代码页,码表等概念,参见这篇文章:

Java为什么选择unicode字符集?字符编码的那些事

 

 

 

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

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值