Windows上.java和.class文件字符集编码关系并包括C/C++上的类同分析

【摘要】Windows系统默认采用GBK字符集,因此导致无法使用UTF-8解码。本文在首先说明Windows上使用的字符集,后分析了JAVA下.java、.class、javac之间的字符集关系,以及分析了VS的C/C++项目的源文件、二进制文件与编译器间的字符集关系。最后总结:在javac的使用中,最好采用-encoding参数指明.java文件使用的字符集,以免造成不可恢复的中文乱码
【问题重现】
JAVA项目中,由于源文件存储采用不同的字符集导致项目输出乱码。当采用GBK存储源文件,正常符出”中文“,而采用UTF-8存储源文件,却输出乱码。
下图为采用UTF-8存储源文件,却输出乱码:

下图为采用GBK存储源文件,正常输出:

【一、Windows系统默认字符集】
1980年,中国制定了GB2310-80,一共收录了7445个字符。1993年,Unicode 1.1版本推出,收录20902个汉字,中国制定了等同于Unicode 1.1版本的“GB 13000.1-93”,简称为GB13000。微软对GB2312-80扩展,并收录了GB13000和Unicode1.1之中的汉字,制定了GBK编码。在Windows中使用代码页CP936表示。如下图,在控制台中使用chcp命令可以查看Windows使用的字符集。
GBK是Windows中文系统默认的字符集

【二、VS下C/C++项目源文件、二进制文与编译器的关系】
笔者使用的VC编译器版本是19.00.24210,使用的VS版本的VS2015。
众所周知,每个文件保存时都会选择指定的字符集,即源文件在Windows上的保存时使用的字符集可以选择GBK和UTF-8形式,在中文的Windows 7系统上,VS默认存储源文件的字符集是GBK。
使用VC编译器编译成二进制可执行文件后,二进制文件所使用的字符集符合以下表格。其中带BOM的UTF8表示在文件开头使用三个字符作为BOM头,标识文件采用的是UTF8字符集

源文件字符集 编译后的二进制文件字符集
GBK GBK
UTF-8(带BOM) GBK
UTF-8 UTF8


【三、JAVA下.java、.class、JVM、输出控制台之间的关系】
在阿里,许多人使用intellij idea作为IDE开发JAVA应用,而intellij idea默认使用UTF8字符集,如下图,IDE Encoding表示整个IDE使用UTF8编码,Project Encoding表示本项目使用UTF8编码。

JAVA下,.java文件和.class文件的字符集关系如下表,比如对于.java中的“中文”字符串str,.class中的字符串有三种情况:①.java以GBK格式保存,即str以GBK格式保存内容“中文”,经过javac编译后,.class中str变为UTF-8保存的"中文“;②.java以UTF-8(无BOM)保存,即str以UTF-8保存内容”中文“,经过javac编译后,.class中str变为UTF-8保存的"涓枃",变为乱码;③.java以UTF-8(有BOM)保存,无法通过编译。

.java文件字符集 .class文件字符集
GBK UTF-8
UTF-8(无BOM) UTF-8(但是中文已经乱码)
UTF-8(有BOM) 编译失败无法生成.class文件


针对上述的第二种情况,为什么.class保存了UTF-8的乱码呢?这是由于.class一定是使用unicode字符集,即兼容UTF8,而.java可以使用任意字符集。JAVA的生成过程使用字符集如下:”.java(任意编码) —> .class(Unicode) —> JVM内(Unicode)“。生成乱码是由于javac把UTF8格式的.java文件当成了GBK格式,因为javac中可以通过-encoding指定.java的字符集,而没有指定的情况将默认.java为系统采用字符集。由于没有使用-encoding,javac将已经是UTF-8的.java文件当成GBK文件处理,从而导致乱码。具体可见:https://www.zhihu.com/question/30977092 

posted on 2016-08-23 17:49  ycloneal  阅读(454)  评论(0编辑  收藏  举报