我打开Windows记事本,输入18
,然后将文件另存为utf-8编码。我知道,我的文件将带有BOM表头,并且我的文件是utf-8编码的文件(带有BOM表头)。
问题是,当通过以下代码打印该字符串时:
//str is that string read from the file using StandardCharsets.UTF_8 encoding
System.out.println(str);
在Windows中,我得到了:
?18
但是在Linux中,我得到了:
18
那么为什么Java的行为不同?如何理解?
答案 0 :(得分:1)
BOM是零宽度的空间,因此原则上不可见。
但是,Window没有UTF-8编码,但是使用了许多单字节编码之一。从String到输出的转换会将字符集中缺少的BOM变成问号。
记事本仍然可以识别BOM并显示UTF-8文本。
当今的Linux通常使用UTF-8,因此在控制台中也没有问题。
进一步的解释
在Windows System.out
上使用控制台,例如,该控制台用作实例Cp-850(约256个字符的单字节字符集)的字符集/编码。很有可能是ĉ
或BOM字符缺失。如果java字符串包含这些字符,则不能将它们编码为256个可用字符之一。因此,它们将被转换为?
。
String s = ...
CharsetEncoder encoder = Charset.defaultCharset().newEncoder();
if (!encoder.canEncode(s)) {
System.out.println("A problem");
}
Windows通常也以单字节编码运行,例如Cp-1252。再次为256个字符。但是,编辑器可能会处理几种编码,如果字体可以表示字符(Unicode代码点),则一切正常。
答案 1 :(得分:0)
java的行为相同,FileInputStream
不处理bom。
在Windows中,您的文件为file1
,十六进制的file1为EF BB BF 31 38
在linux中,您的文件为file2
,file2的十六进制为31 38
阅读它们时,您会得到不同的字符串。
我建议您使用记事本++将bom文件转换为无bom文件。
或者您可以使用BOMInputStream