总结一下自己最近学习到的Java编码相关知识
与编码有关的系统属性
通过下面代码可以获得当前所有系统变量:
System.getProperties().store(new FileOutputStream("SysProps.txt"),"");
查看SysProp.txt可以看到两个有关编码的属性,file.encoding和sun.jnu.encoding。它们的默认值与当前操作系统的默认编码一致。
file.encoding
作用
- 读写文件时默认使用的编码
- 输出时默认使用的编码
- URLEncoder.encode(String str)等等类似api的默认使用的编码
综上不难看出,一般未指定编码的情况下,所有和编码有关的函数都会按照file.encoding的值确定要使用哪个字符集。
这里拓展一下。在tomcat中resp的writer的字符集并不是由file.encoding确定。tomcat获得的resp的writer是自己实现的,只不过是继承了PrintWriter,如果需要指定writer的字符集,则需要用tomcat提供的函数去修改指定。
指定file.encoding的值
在命令行界面,用java命令运行指定class文件时,添加参数:
-Dfile.encoding=(字符集)
此时file.encoding为指定值。如果没有添加这个参数的话,file.coding的值和操作系统默认编码一致。
很多ide会在运行class文件时自动加上 -Dfile.encoding=(字符集) 这一选项,所以在ide中运行可能看到的file.encoding是别的值,而直接用命令行运行,会显示操作系统默认的编码。
sun.jnu.encoding
作用
sun.jnu.encoding的作用很少,由上面也可以看出来,基本上运行时的编码问题都和file.encoding有关。
- 运行class文件时,查找class文件名所用的编码
- 运行class文件时,添加的中文参数所用的编码
可以发现sun.jnu.encoding基本是和java命令有关。java命令后面跟的参数,class文件名,默认情况下都是操作系统的默认编码。
指定sun.jnu.encoding的值
如果这个时候添加参数:
-Dsun.jnu.encoding=(字符集)
则参数,class文件名都会按照指定的字符集编码。这时如果和操作系统默认的编码不一致的话,参数会发生乱码,class文件名也会报错,提示找不到该文件。
java文件,class文件编码相关问题
java文件字符集是保存java文件时所选用的字符集。与java文件不同,被编译成二进制文件的class文件里存的都是字符的utf-8的值。
由于最终在class文件中字符串都是以utf-8格式编码,所以可以肯定的是出现了乱码问题肯定与java文件的编码格式无关。
这里拓展一下在idea中的情况。idea设置中有一个选项是File | Settings | Editor | File Encodings。和上面所讨论的file.encoding不同,这里所指定的值影响的是java文件这样的文本文件所采用的编码。例如,在该设置下如果设置Global Encoding为utf-8,那么所有的文本文件都会采取该字符集,省去了给每个文件单独设置的麻烦,这样如果是在idea中创建一个java文件,就默认使用了utf-8编码。
javac命令编码相关问题
javac命令中有一个选项是:
-encoding (字符集)
它指定了用什么字符集去解析java文件,如果不添加该选项的话,默认使用操作系统的默认编码。
很多ide也在运行编译java文件时自动添加了该选项。例如,javac命令默认是使用操作系统的默认编码去解析源文件(中文系统下一般都是gbk编码),而我们在ide中运行utf-8编码的java文件并不会报错,这是因为ide一般都会加上 -encoding (当前java文件所用字符集) 这一选项。
控制台/命令提示符 下编码问题
在Windows中有一个命令是控制当前控制台的编码的:
chcp (对应字符集的号码)
其中gbk的号码是936,utf-8的号码是65001。如果只是输出chcp命令的话,则会显示当前页所用的字符集号码
如果当前控制台编码与Java输出所用编码不一致的话,就会出现乱码。例如,一个很常见的问题就是Tomcat输出日志乱码。
这里拓展一下在idea中的情况。idea设置中有一个选项是 File | Settings | Editor | General | Console 。这里指定的字符集就是idea控制台的编码。比如当前系统属性file.encoding的值是gbk,而控制台设置的编码是utf-8,那么下面代码的输出将会出现乱码:
System.out.println("你好世界");