在javac命令中,encoding表示在进行编译时会使用什么样的编码去读源文件。那么针对以下的代码:
//源文件使用ide默认编码 UTF8编码 String s = "中文测试代码"; OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream("d:/t.txt")); writer.write(s); writer.close();
对以上的utf8源代码,我们在cmd下分别使用以下3种命令进行编译并执行(中文版windows7操作系统)。
- 编译1 javac T.java
- 编译2 javac -encoding GBK T.java
- 编译3 javac -encoding UTF8 T.java
执行命令均为 java T
在最终的输出文件中,我们使用系统自带记事本打开相应的输出文件t.txt,会发现。3种编译的class文件在同一种执行命令下均能够正常显示相应的文字,并且没有乱码发生。
这里面就涉及到了默认编码,编码以及互相转换的问题,这里不涉及编码之间复杂的关系,只是从生成的class文件以及文件的执行上分析这里的运行结果。
javac默认编码
在javac中,如果在编译时不指定编码,那么就使用系统的默认编码。win7中文系统默认编码为GBK,因此上面的编译1和编译2效果是一样的。
java默认编码
在进行执行时,如果未指定编码(通过-Dfile.encoding=XX)指定,则使用系统默认编码。win7中文系统为GBK。
encoding参数
官方的参数说明为:指定源文件使用的字符编码。
这就意味着,如果我们指定了参数,javac就会使用我们指定的参数去读取源文件,并进行编译。
GBK编译
经过gbk编译之后的class文件中,上面的中文字符会经过以下几个过程。
//字符格式(6个字符): 中文测试代码 //源文件存储时UTF8文件格式(18个字节),每个字符为3个字节组成 E4 B8 AD E6 96 87 E6 B5 8B E8 AF 95 E4 BB A3 E7 A0 81 //读取源文件,GBK转码格式9个字符,每2个字节组成一个汉字,全成乱码了... 涓枃娴嬭瘯浠g爜 //class文件存储,UTF8存储格式(27个字节),每个字节由3个字节组成 E6 B6 93 EE 85 9F E6 9E 83 E5 A8 B4 E5 AC AD E7 98 AF E6 B5 A0 EF BD 87 E7 88 9C
这个过程可以归纳为 UTF8字节被读取为GBK字符,再转换为UTF8字节 的过程。由于第一步是读取而不是转换,因此源文件(UTF8编码),存储为18个字节,但最终到Class文件存储时(utf8串)就成了27个字节。实际的class文件存储如下所示:
在使用java执行时,又会按照以下的顺序进行处理。
//class文件存储,UTF8存储格式(27个字节),每个字节由3个字节组成 E6 B6 93 EE 85 9F E6 9E 83 E5 A8 B4 E5 AC AD E7 98 AF E6 B5 A0 EF BD 87 E7 88 9C //执行时字符格式,9个字符 涓枃娴嬭瘯浠g爜 //输出时编码,18个字节 E4 B8 AD E6 96 87 E6 B5 8B E8 AF 95 E4 BB A3 E7 A0 81 //输出到文件存储格式 E4 B8 AD E6 96 87 E6 B5 8B E8 AF 95 E4 BB A3 E7 A0 81
即在执行时,在运行过程中仍然是乱码的字符信息。但进行编码时,如果是GBK编码(java编码参数),因此9个字符又重新编码为18个字节,并最终输出到文件中。
这里注意看,这18个字节的格式,实际上就是刚才的6个字符。因此用记事本打开时,windows能够猜到这个编码为utf8,正好可以正常打开。
UTF8编译
编译处理过程
//字符格式(6个字符): 中文测试代码 //源文件存储时UTF8文件格式(18个字节),每个字符为3个字节组成 E4 B8 AD E6 96 87 E6 B5 8B E8 AF 95 E4 BB A3 E7 A0 81 //读取源文件,UTF8进行转码,正好转换为原来的字符 中文测试代码 //class文件存储,UTF8存储格式(18个字节),每个字节由3个字节组成 E4 B8 AD E6 96 87 E6 B5 8B E8 AF 95 E4 BB A3 E7 A0 81
可以看出,使用UTF8编译时输出到class文件中和编译和源文件存储一致。如图下所示:
那么进行执行时呢?则是按照以下的处理过程处理:
//class文件存储,UTF8存储格式(27个字节),每个字节由3个字节组成 E4 B8 AD E6 96 87 E6 B5 8B E8 AF 95 E4 BB A3 E7 A0 81 //执行时字符格式,6个字符 中文测试代码 //输出时编码,12个字节,GBK编码 D6 D0 CE C4 B2 E2 CA D4 B4 FA C2 EB //输出到文件存储格式 D6 D0 CE C4 B2 E2 CA D4 B4 FA C2 EB
这样的话,输出到文件当中的数据则为12个字节,正好是GBK编码的字符。因此记事本打开也没问题。
GBK编译时奇数字符
在文中,我们的中文字符为偶数个,因此在进行GBK转码时能够正常转码。如果为奇数个呢,比如5个,UTF8编码为15个字节,那么进行编译时,由于无法转码,就会报以下错误:
总结
从上面的编译过程中,我们可以看出。使用默认的编码处理,可能是一种凑巧的结果。而在实际过程中,如果我们需要保证编码的正确性,避免乱码。最好保持文件,编译,执行3者的编码都是统一的。
转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201405250001.html