我最近注意到,当使用utf-8-sig
编码追加到文件时,Python会以非常明显的方式运行。见下文:
>>> import codecs, os
>>> os.path.isfile('123')
False
>>> codecs.open('123', 'a', encoding='utf-8-sig').write('123\n')
>>> codecs.open('123', 'a', encoding='utf-8-sig').write('123\n')
以下文字以文件结尾:
<BOM>123
<BOM>123
这不是一个错误吗?这是不合逻辑的。 任何人都可以向我解释为什么会这样做? 为什么只有当文件不存在并且需要创建时,他们才设法预先添加BOM?
答案 0 :(得分:8)
不,这不是一个bug;这是完全正常的预期行为。编解码器无法检测已经写入文件的数量;例如,您可以使用它附加到预先创建但空的文件。该文件不是新文件,但它也不包含BOM。
然后还有其他用例,其中编解码器用于流或字节串(例如,不用codecs.open()
),其中根本没有文件进行测试,或者开发人员希望始终在输出开始时强制执行BOM。
仅在新文件上使用utf-8-sig
;每当您使用它时,编解码器总是写出BOM。
如果您直接使用文件,您可以自己测试一下;请改用utf-8
并手动编写BOM,这只是一个编码U+FEFF ZERO WIDTH NO-BREAK SPACE:
import io
with io.open(filename, 'a', encoding='utf8') as outfh:
if outfh.tell() == 0:
# start of file
outfh.write(u'\ufeff')
我使用较新的io.open()
代替codecs.open()
; io
是为Python 3开发的新I / O框架,根据我的经验,它比codecs
更强大,可以处理编码文件。
请注意,UTF-8 BOM实际上是无用的。 UTF-8 没有可变字节顺序,因此只有一个字节顺序标记。另一方面,UTF-16或UTF-32可以用两个不同的字节顺序之一编写,这就是需要BOM的原因。
Microsoft产品主要使用UTF-8 BOM来自动检测文件的编码(例如不其中一个遗留代码页)。