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('123\n')
>>> codecs.open('123', 'a', encoding='utf-8-sig').write('123\n')

Следующий текст заканчивается в файле:

<BOM>123
<BOM>123

Разве это не ошибка? Это так не логично. Может ли кто-нибудь объяснить мне, почему это было сделано так? Почему им не удалось добавить спецификацию только тогда, когда файл не существует и его нужно создать?


person astronaut    schedule 18.04.2014    source источник
comment
Нет, это не ошибка; это вполне ожидаемое поведение. Кодек не может определить, сколько уже записано в файл.   -  person Martijn Pieters    schedule 18.04.2014


Ответы (1)


Нет, это не ошибка; это совершенно нормальное, ожидаемое поведение. Кодек не может определить, сколько уже записано в файл; например, вы можете использовать его для добавления к предварительно созданному, но пустому файлу. Файл не был бы новым, но и не содержал бы спецификации.

Кроме того, есть другие варианты использования, когда кодек используется в потоке или байтовой цепочке (например, не с codecs.open()), когда нет вообще никакого файла для тестирования, или когда разработчик хочет применить спецификацию в начало вывода, всегда.

Используйте utf-8-sig только для нового файла; кодек будет всегда записывать спецификацию всякий раз, когда вы ее используете.

Если вы работаете напрямую с файлами, вы можете протестировать для начала самостоятельно; вместо этого используйте utf-8 и напишите спецификацию вручную, которая представляет собой просто закодированный U+FEFF НУЛЕВАЯ ШИРИНА НЕРАЗРЫВНЫЙ ПРОБЕЛ :

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, и, по моему опыту, она более надежна, чем codecs для обработки закодированных файлов.

Обратите внимание, что спецификация UTF-8 на самом деле практически бесполезна. UTF-8 не имеет переменного порядка байтов, поэтому существует только один знак порядка байтов. UTF-16 или UTF-32, с другой стороны, могут быть записаны с одним из двух различных порядков байтов, поэтому необходима спецификация.

Спецификация UTF-8 в основном используется продуктами Microsoft для автоматического определения кодировки файла (например, не одной из устаревших кодовых страниц).

person Martijn Pieters    schedule 18.04.2014