咱们在开发过程当中,特别是多种编码格式并存的状况下,很容易遇到乱码问题。 假若有一个GBK编码java文件,而后再使用-Dfile.encoding=GBK参数,写入的文件中哪些是乱码呢。那若是使用UFT-8编码的java文件呢。java
public class Main { static String content = "中文"; public static void main(String[] args) throws IOException { OutputStreamWriter gbkWriter =new OutputStreamWriter(new FileOutputStream("GBK-FILE"),"GBK"); // 状况一、二、5的结果确定是一致的 gbkWriter.write(content+"\n"); //(1) gbkWriter.write(new String(content.getBytes("GBK"),"GBK")+"\n"); // (2) gbkWriter.write(new String(content.getBytes("GBK"), "UTF-8")+"\n"); // (3) gbkWriter.write(new String(content.getBytes("UTF-8"),"GBK")+"\n"); // (4) gbkWriter.write(new String(content.getBytes("UTF-8"), "UTF-8")+"\n"); // (5) gbkWriter.flush(); gbkWriter.close(); } }
其实用一张图就能够清晰的归纳出从java文件编译到输出的过程 主要有3个地方的编码转换:linux
上图①所示的位置,其实就是windows
javac -encoding xxx数组
的时候控制,若是你没有显示的指定编码,那么会根据当前操做系统的默认编码格式进行编译,通常windows是gbk,linux是UTF-8。若是这里编码指定错了,那么你的代码颇有可能出现中文乱码问题,注意是颇有可能,而不是绝对。缘由后面会说到。编译出来的class文件统一都是UTF-8格式jvm
当class文件加载的jvm的时候,也会进行字符串编码转换,和前面同样,会使用操做系统默认的编码格式,这里的编码不是指class文件的编码,而是指java文件的编码格式,相似于指定java文件是什么编码格式编译为class文件的。就是jvm参数:编码
java -Dfile.encoding=xxx操作系统
在java运行过程当中,字符串在内存中则是使用**Unicode(UTF-16)**进行存储的。而UTF-8转换为UTF-16是很简单的过程。当咱们标用String.getBytes()时候,则是把内存中的unicode转换对应的字节数组。(若是没有指定,则使用操做系统默认的编码格式)。能够看出,把一个字符串从编译到内存,实际上是经历的过程为:code
编译文件编码->加载jvm编码->unicode图片
输出的编码则是在代码中指定的。例如:内存
OutputStreamWriter gbkWriter =new OutputStreamWriter(new FileOutputStream("GBK-FILE"),"GBK");
若是理解上面的,咱们再看看文章一开始的例子。举几个例子作说明,其余的状况也就逐类旁通。
状况1是比较好理解的,由于java文件编码、编译、加载都是使用GBK,加载到内存中Unicode确定也是正常的,那么打印出来也是正常的。
在状况1的前提下(即加载到内存中是正常的),在jvm中使用GBK解码在编码确定是正常的。
在状况1的前提下,使用不一样的解码和编码,确定是乱码
当咱们使用UTF-8的格式打开文件的时候,状况(4)是正常的,其他都是乱码。实际上是由于先使用unicode进行转换为UTF-8格式的Byte数组,生成的字符串虽然乱码和写文件的格式都是GBK,至关于原封不动的UTF-8格式的byte数组写到文件中,因此就会出现这个状况
这个例子就是直至加载到内存都是正常的状况下,在jvm内进行编码和解码致使乱码的状况
状况1是乱码,说明字符串加载到内存中就已是乱码了。由于UFT-8格式使用GBK进行编码,在生成class文件就已是乱码了。
状况3为何又是正常的呢,其实这是误打误撞类型。我的理解的形成这个状况的缘由有:
为何是使用UTF-8打开状况1不是乱码了呢,其实和上面误打误撞,只不过以前发生在内存中的GBK->UTF-8换为咱们在打开文件的时候进行的编码转换,状况一、二、5结果确定一致的
和例子1不同,例子2是在生成class文件就已是乱码的状况。这就是前面所说的,生成class乱码,但输出不必定是乱码。
一句话:必定要保证java文件、编译、加载class文件、输出的编码格式一致。若是出现了乱码,能够从这几个阶段进行排查。