windows 使用 UTF-8 编码编写程序(比如 java)会遇到乱码问题。这是因为 windows 本身的默认编码为GBK而不是UTF-8,对应的 windows 下控制台cmd,powershell 的默认显示编码也不是 UTF-8。而系统中安装的编译器本身无从得知一个源代码文件究竟是如何编码的,因而默认采用了系统字符编码,从而导致了问题的发生
永久链接:http://blog.ryjer.com/posts/a11ba50a6.html
原因
java 编译器和java虚拟机并不能知道 .java 源代码文件的字符编码,因为现有的文件系统不会提供该信息。所以 java 需要去 “猜” 源代码文件究竟是什么编码(其他的编译器也需要猜)。
而对于像源代码文件一类的“文本文件”,其编码最有可能采用的就是系统默认的字符编码。而各个操作系统(windows、linux)会在环境变量中向系统中的所有进程提供系统默认字符编码信息。windows 中文版系统默认编码为 GBK,当然(微软传统),是微软自己理解的GBK,并不完全是国标GBK。
所以java会从环境变量中读取当前操作系统的字符编码信息,并将其作为源代码等 java 相关文件的字符编码。
java编译器内部使用的是 Unicode 编码,其只能处理unicode 编码的源代码文件。所以在编译前会先将源代码文件转换为内部的 Unicode编码,然后再进行编译。
当你在windows 下使用 默认字符集为UTF-8 文本编辑器编写 java 源代码时,产生的 .java
源代码文件是与系统默认编码GBK不同的UTF-8 编码文件。而 javac 编译器无法知道这个文本文件到底是什么字符编码,只能将其视作最有可能的系统默认字符编码——GBK编码处理。由于GBK和UTF-8之间的一些差异,在进行 java 外部源代码GBK编码向 java编译器内部Unicode 编码转换时出现了无法转换的问题。便出现了 错误:编码GBK的不可映射字符
问题。比如下面这样
1 | $ javac AllTheColorOFTheRainBow.java |
解决方案
知道了javac 编译命令和Java -jar等命令出现字符编码错误的原因,就可以进行针对性解决。主要有以下3种方法,但长期建议使用方法3,短期使用建议采用方法2
1. 修改系统默认字符集编码
该方法建议在 linux 系统上使用,而不建议在 windows 上使用。因为 windows 对 UTF-8 的支持还是不稳定的 beta 版本。
如果你一定要这么做的话,可以按照如下步骤设置。首先,打开 控制面板
> 时钟与区域
然后点击 区域
接着,点击上方 管理
更改系统区域设置
勾选下图红框所示的选项后,点击 确定
完成系统字符集更改
再强调一下,不建议这么做。而是建议使用下面介绍的方法3添加 JAVA_TOOL_OPTIONS
环境变量
2. 手动指定源代码文件的编码字符集
javac 等命令支持手动指定目标文件的编码,这样它们就不用根据系统默认字符集去猜测编码了。
你可以使用 -encoding UTF-8
参数指定文件内的字符编码为 UTF-8,从而显式指明源代码文件的字符集编码。比如,在使用javac 编译命令时可以像如下这样
1 | javac -encoding=UTF-8 AllTheColorOFTheRainBow.java |
这次再来编译 AllTheColorOFTheRainBow.java
就不会出现中文乱码问题了。
3.添加指定命令参数的环境变量 JAVA_TOOL_OPTIONS
可以通过 JAVA_TOOL_OPTIONS
为系统中java工具包提供额外信息。与之对应,-Dfile.encoding
参数就可以指定java的默认字符集。使得java 工具不再根据系统默认编码处理源代码文件,而是用通过 -Dfile.encoding
指定的编码来处理源代码。你可以通过如下方式指定 java 工具的默认字符集为 UTF-8
在 windows 环境变量中添加一个系统变量 JAVA_TOOL_OPTIONS
,其值为 -Dfile.encoding=UTF-8
。如果你不知道如何添加环境变量,可以参考这篇文章:如何编辑 windows 10 环境变量
然后点击 确定
,回到主编辑窗口,你会发现下图红框所示刚刚被添加的环境变量 JAVA_TOOL_OPTIONS
点击上图所示的 确定
,回到 系统属性
再点击上图中的确定,完成添加
测试
我这里使用 git bash,其实你用 cmd 、powershell 或者 windows Terminal 都可以。这里使用 javac 编译命令进行测试,其结果如下图所示
1 | $ javac AllTheColorOFTheRainBow.java |
可以看到,javac 命令自动获取了 JAVA_TOOL_OPTIONS
环境变量信息:Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
依然乱码
如果你上面配置完成后依然乱码,那可能不是或者不仅仅是 java的问题。也可能是你所使用的 shell(或者说是终端) 本身的编码问题,你需要去修改你所使用的终端的默认字符集。
修改 cmd 显示编码
windows下最常见的终端就是cmd,其默认编码一般与系统相同,在中文下是 GBK而不是网络上较为常用的 UTF-8。
你可以使用 chcp
命令修改 cmd 终端的默认字符集,其格式为
1 | chcp 编码代号 |
不同的代号代表不同的编码,常用的代号如下
1 | # 编码格式 chcp 代号 |
所以,要更改显示字符集为 UTF-8的命令是
1 | chcp 65001 |
你在 cmd 中执行以上命令即可更改 cmd 的默认字符集为 UTF-8