utf 8-python utf-8-sig BOM在追加到末尾时位于文件的中间



我最近注意到,Python在使用utf-8-sig编码附加到文件时的行为非常不明显。见下文:

>>> import codecs, os
>>> os.path.isfile('123')
False
>>> codecs.open('123', 'a', encoding='utf-8-sig').write('123n')
>>> codecs.open('123', 'a', encoding='utf-8-sig').write('123n')

以下文本以文件结尾:

<BOM>123
<BOM>123

那不是虫子吗?这是不合逻辑的。有人能向我解释为什么这么做吗?为什么他们不设法只在文件不存在并且需要创建时才准备BOM?

不,这不是一个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是为Python3开发的新I/O框架,根据我的经验,在处理编码文件方面比codecs更健壮。

请注意,UTF-8 BOM几乎毫无用处。UTF-8没有可变字节顺序,因此只有一个字节顺序标记。另一方面,UTF-16或UTF-32可以用两个不同字节顺序中的一个来编写,这就是为什么需要BOM的原因。

UTF-8 BOM主要由Microsoft产品用于自动检测文件的编码(例如而不是其中一个遗留代码页)。

最新更新