不带BOM的UTF-8编写

9

这段代码,

OutputStream out = new FileOutputStream(new File("C:/file/test.txt"));
out.write("A".getBytes());

And this,

OutputStream out = new FileOutputStream(new File("C:/file/test.txt"));
out.write("A".getBytes(StandardCharsets.UTF_8));

在我看来,下面两种方法都能产生相同的结果,即UTF-8无BOM。然而,Notepad++没有显示任何有关编码的信息。我期望Notepad++在这里显示以UTF-8无BOM编码保存,但是在“编码”菜单中未选择任何编码。

现在,这段代码会以UTF-8带BOM编码方式写入文件。

 OutputStream out = new FileOutputStream(new File("C:/file/test.txt"));
 byte[] bom = { (byte) 239, (byte) 187, (byte) 191 };
 out.write(bom);
 out.write("A".getBytes()); 

Notepad++显示编码类型为UTF-8编码

问题:前两个代码写入没有BOM的UTF-8文件有什么问题?我的Java代码是否正确?如果是,那么notepad++尝试检测编码类型是否有问题?

Notepad++只是猜测吗?


1
字母A可能是UTF-8、ISO-646、ISO-8859-1、ISO-8859-2等编码方式之一。Notepad++无法猜测您是否在使用UTF-8编码。 - bmargulies
如果您没有指定编码(第一个示例),JVM 将使用操作系统的默认编码(Windows 的 ANSI,Linux 的 UTF-8)。 - Lluis Martinez
2个回答

17

使用UTF-8编写的"A"文件没有BOM与使用ASCII或ISO-8859-*或任何其他兼容ASCII编码的编写的"A"文件 完全相同。该文件包含一个十进制值为65的单个字节。

可以这样理解:

  • "A".getBytes("UTF-8") 返回一个 new byte[] { 65 }
  • "A".getBytes("ISO-8859-1") 返回一个 new byte[] { 65 }
  • 将这些调用的结果写入文件中
  • 文件的使用者如何区分这两种情况?

在该文件中没有任何提示需要使用UTF-8进行解码。

尝试编写"Käsekuchen"或其他无法编码为ASCII的内容,并查看Notepad ++是否正确猜测编码(因为这正是它所做的:做出有根据的猜测,没有元数据告诉它要使用哪种编码)。


你的意思是notepad++只是在猜测吗? - Mawia
9
@Mawia:是的,没错。 "普通文本" 没有元数据可以告诉它编码(当然,如果有BOM,则除外),因此它使用一组启发式规则来猜测最可能的编码。而这并不是 Notepad++ 的错:除了猜测以外,你几乎没有什么可以做的了(你可以每次询问用户,但那会很快变得很烦人)。 - Joachim Sauer
好的,我认为这很有道理,因为当我用UTF-16编写它时,notepad ++显示为“在UCS-2大端编码中编码”。所以,notepad ++只是在猜测,对吗? - Mawia
3
@Mawia:我已经在回答中写明它是猜测,我还在上面的评论中确认了这一点。您还在等待第三次确认吗?;-) 一些编码比其他编码具有更“明显”的特征:例如,UTF-16通常可以通过每隔一个字节为0(对于英语文本)的方式检测出来,而UTF-8则可以通过一些常见的序列(以及其他不能出现在其中的字节序列)进行检测。其他编码可以通过字节值的统计分析来“检测”。但所有这些都只是猜测。 - Joachim Sauer

0

我不确定我的答案是否正确,但让我在这里表达我的理解:

如上所述,如果您只写“A”,Notepad++无法理解它是哪种类型的编码。但是,如果您想要Notepad++像下面的图示一样显示“以UTF-8编码而无BOM”,则需要进行设置。

enter image description here

然后你必须欺骗Notepad++,你可以使用以下代码来实现: enter image description here

如果你想让notepad++显示“以UTF-8编码”,那么你应该从osw.write("\uFEFF")中删除子字符串部分,因为这是一个BOM字符,你正在尝试插入它。当你插入这个字符时,文件编码类型将变成“以UTF-8编码”,当你通过编程方式删除它时,它将变成“不带BOM的UTF-8编码”,因为你已经删除了这个BOM字符。

你还需要改变Notepad++的首选项设置,如下所示, 只有这样,Notepad++才能识别你想要的编码。

enter image description here

然而,如果你只是简单地写文本,Notepad++会将其视为“ANSI”。

希望我的解释清楚,并且我的分析能够帮助到某些人。 然而,这种方法只是一个变通方法,在无奈的情况下才使用。

如果你不想改变Notepad++的偏好设置,但仍然想要编码为“不带BOM的UTF-8编码”,那么你必须像这样做:

enter image description here

我在我的博客这里可能以更好的方式解释了同样的事情。


1
更好的理解请点击此处 - HookUp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接