天下脸皮共十分
我占八分

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

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

赞(0) 打赏
未经允许不得转载:Stephen Young » 从内存角度解析Java字符编码
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏