Запись в файл UTF-8 на Python
Я действительно путаю с codecs.open function
. Когда я это сделаю:
file = codecs.open("temp", "w", "utf-8")
file.write(codecs.BOM_UTF8)
file.close()
Это дает мне ошибку
UnicodeDecodeError: 'в кодировке ASCII' кодек не может декодировать байт 0xef в положении 0: порядковый номер не в диапазоне (128)
Если я это сделаю:
file = open("temp", "w")
file.write(codecs.BOM_UTF8)
file.close()
Это прекрасно работает.
Вопрос состоит в том, почему первый метод терпит неудачу? И как мне вставить спецификацию?
Если второй метод является правильным способом его выполнения, какой смысл использовать codecs.open(filename, "w", "utf-8")
?
4 ответа:
Я полагаю, что проблема заключается в том, что
codecs.BOM_UTF8
является строкой байтов, а не строкой Юникода. Я подозреваю, что обработчик файлов пытается угадать, что вы на самом деле имеете в виду, основываясь на "Я должен писать Unicode как кодированный UTF-8 текст, но вы дали мне байтовую строку!"Попробуйте записать строку Unicode для метки порядка байтов (то есть Unicode U+FEFF) напрямую, чтобы файл просто кодировал ее как UTF-8:
import codecs file = codecs.open("lol", "w", "utf-8") file.write(u'\ufeff') file.close()
(похоже, это дает правильный ответ-файл с байтами EF BB БФ.)
EDIT: предложение С. Лотта использовать "utf-8-sig" в качестве кодировки лучше, чем явно писать BOM самостоятельно, но я оставлю этот ответ здесь, поскольку он объясняет, что было неправильно раньше.
Прочитайте следующее: http://docs.python.org/library/codecs.html#module-encodings.utf_8_sig
Сделай это
with codecs.open("test_output", "w", "utf-8-sig") as temp: temp.write("hi mom\n") temp.write(u"This has ♭")
Результирующий файл-UTF-8 с ожидаемой спецификацией.
@S-Lott дает правильную процедуру, но расширяя вопросы Unicode, интерпретатор Python может дать больше информации.
Джон Скит прав (необычно) насчет
codecs
модуль-содержит байтовые строки:>>> import codecs >>> codecs.BOM '\xff\xfe' >>> codecs.BOM_UTF8 '\xef\xbb\xbf' >>>
Выбирая другой nit,
BOM
имеет стандартноеUnicode имя, и его можно ввести как:>>> bom= u"\N{ZERO WIDTH NO-BREAK SPACE}" >>> bom u'\ufeff'
Он также доступен через
unicodedata
:>>> import unicodedata >>> unicodedata.lookup('ZERO WIDTH NO-BREAK SPACE') u'\ufeff' >>>
Я использую команду file *nix для преобразования неизвестного файла кодировки в файл utf-8
# -*- encoding: utf-8 -*- # converting a unknown formatting file in utf-8 import codecs import commands file_location = "jumper.sub" file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location) file_stream = codecs.open(file_location, 'r', file_encoding) file_output = codecs.open(file_location+"b", 'w', 'utf-8') for l in file_stream: file_output.write(l) file_stream.close() file_output.close()