Java 之 Charset.defaultCharset()
简述
以一个故事^1开局。IDEA 在使用 Gradle 时可能会输出乱码,常见的解决方式是 Custom VM Options 里面增加 -Dfile.encoding=UTF-8
。但故事作者通过细致分析找到问题的关键,不同系统间的编解码。
以常见的报错信息为例,自 JavacMessage.getLocalizedString(Locale, ...)
诞生, Gradle DaemonPrintStreamLoggingSystem
(javac.util.LogPrintWriter
) 接收,并使用 StandardOutputListener
(TextStreamOutputEventListener
) 通过 LogToClient$AsynchronousLogDispatcher
发送该信息,随后StreamBackedStandardOutputListener
吐给 IDEA。但 IDEA 一律按 UTF-8 处理^2,在此处露出了马脚。
当然,这也不是甚问题,因为编码问题由来已久,Intellij Community 在2019年就已经做出选择,specify UTF_8 charset explicitly^3.
Charset.defaultCharset()
java.nio.charset.Charset.defaultCharset()
/**
* Returns the default charset of this Java virtual machine.
*
* <p> The default charset is determined during virtual-machine startup and
* typically depends upon the locale and charset of the underlying
* operating system.
*
* @return A charset object for the default charset
*
* @since 1.5
*/
public static Charset defaultCharset() {}
如 defaultCharset() 方法文档所述,该值的确定时间很早,且一般与系统设置有关。
确定时间早,System.initPhase1()
就完成确定,与 GetJavaProperties 有关。
系统,Unix 有 setlocale
的 <language name>_<country name>.<encoding name>
,Windows 有 GetLocaleInfo
之类的。
可通过 file.encoding
进行配置。
相关
- JEP 226: UTF-8 Property Resource Bundles
- JEP 254: Compact Strings
- JEP 400: UTF-8 by Default
附加
Unicode 中文乱码速查表(部分)^4
示例 | 产生原因 | |
古文码 | 鐢辨湀瑕佸ソ濂藉涔犲ぉ澶╁悜涓? | 以 GBK 方式读取 UTF-8 编码的中文 |
口字码 | ����Ҫ�¨2�ѧϰ������ | 以 UTF-8 的方式读取 GBK 编码的中文 |
Windows UTF-8
- Windows 设置 > 时间与语言 > 非 Unicode 程序的语言 > 「Beta版:使用 Unicode UTF-8 提供全球语言支持」
- 之前开启后,会有 cmd 代码页、USB 复制失败^5等等问题。
- 现在开启后,暂未遇到。
- cmd 设置 code page
- HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe
参考
- https://juejin.cn/post/7194466056940748859
- <com/intellij/openapi/externalSystem/util/OutputWrapper.java#L38>
- <intellij-community/commit/995b91a5ded47fe4377b8bb2c909ca30cf3d49f4>
- <https://github.com/justjavac/unicode-encoding-error-table>
- <answers.microsoft.com > 错误0x800700ea:有更多数据可用>