我打开 Windows 记事本,输入 18
,并将文件保存为 utf-8 编码。我知道我的文件将具有 BOM header ,并且我的文件是 utf-8 编码文件(带有 BOM header )。
问题是,当通过以下代码打印该字符串时:
//str is that string read from the file using StandardCharsets.UTF_8 encoding
System.out.println(str);
在 Windows 中我得到:
?18
但是在 Linux 中我得到了:
18
那么为什么java的行为会不同呢?怎么理解?
最佳答案
BOM 是一个零宽度空间,因此原则上是不可见的。
但是 Window 没有 UTF-8 编码,而是使用多种单字节编码之一。从 String 到输出的转换会将字符集中缺少的 BOM 转换为问号。
记事本仍然会识别 BOM 并显示 UTF-8 文本。
现在的Linux普遍使用UTF-8,所以没有问题,在控制台也是如此。
进一步说明
在 Windows 上,System.out
使用控制台,并且该控制台例如使用 Cp-850 等字符集/编码,即约 256 个字符的单字节字符集。很可能缺少 ĉ
或 BOM 字符。如果 java 字符串包含这些字符,则它们无法编码为 256 个可用字符之一。因此它们将被转换为 ?
。
使用 CharsetEncoder :
String s = ...
CharsetEncoder encoder = Charset.defaultCharset().newEncoder();
if (!encoder.canEncode(s)) {
System.out.println("A problem");
}
Windows 通常也运行在单字节编码上,例如 Cp-1252。又是 256 个字符。然而,编辑器可能会处理多种编码,如果字体可以表示字符(Unicode 代码点),那么一切都会正常。
关于java在处理带有BOM字符串的utf-8时行为不一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55273476/