Ответ 1
ПРИМЕЧАНИЕ: это было написано для Python 2.x. Не уверен, если применимо к 3.x.
Ваше использование str
для сырых двоичных данных в памяти правильное.
[Если вы используете Python 2.6+, лучше использовать bytes
, который в версии 2.6+ является просто псевдонимом str
, но лучше выражает ваше намерение и поможет, если однажды вы портируете код на Python 3. ]
Как отмечают другие, запись двоичных данных через кодек странно. Кодер записи записывает unicode и выводит байты в файл. Вы пытаетесь сделать это в обратном направлении, следовательно, наше замешательство в ваших намерениях...
[И ваш диагноз ошибки выглядит корректно: поскольку кодек ожидает unicode, Python расшифровывает вашу строку в unicode с системной кодировкой по умолчанию, которая задыхается.]
Что вы хотите видеть в выходном файле?
-
Если файл должен содержать двоичные данные as-is:
Затем вы не должны отправлять его через кодек; вы должны это написать непосредственно в файл. Кодек кодирует все и может испускать действительные кодировки unicode (в вашем случае, действительный UTF-8). Нет ввода, который вы можете дать ему, чтобы он издавал произвольные байтовые последовательности!
- Если вам нужна смесь для UTF-8 и необработанных двоичных данных, вы
должен открывать файл напрямую и смешивать записи
some_data
сsome_text.encode('utf8')
...
Обратите внимание, однако, что смешивание UTF-8 с необработанными произвольными данными очень плохой дизайн, потому что такие файлы очень неудобны для решения с! Инструменты, которые понимают unicode, будут дросселировать на двоичном данных, что оставляет вам не удобный способ даже просматривать (не говоря уже о изменить) файл.
- Если вам нужна смесь для UTF-8 и необработанных двоичных данных, вы
должен открывать файл напрямую и смешивать записи
-
Если вы хотите, чтобы дружественное представление произвольных байтов в юникода
Передайте
data.encode('base64')
в кодек. Base64 производит только чистый ascii (буквы, цифры и небольшая пунктуация), поэтому он может быть четко встроена во что угодно, она явно смотрит на людей как бинарные данные, и он достаточно компактен (чуть более 33% накладные расходы).P.S. вы можете заметить, что
data.encode('base64')
странно.-
.encode()
должен принимать unicode, но я даю ему строка?! Python имеет несколько псевдокодеков, которые преобразуют str- > str таких как "base64" и "zlib". -
.encode()
всегда возвращает str, но вы будете передавать его в кодек ожидая unicode?! В этом случае он будет содержать только чистые ascii, так что это не имеет значения. Вы можете писать явноdata.encode('base64').encode('utf8')
, если это заставляет вас почувствовать лучше.
-
-
Если вам нужно сопоставление 1:1 от произвольных байтов до unicode:
Передайте
data.decode('latin1')
в кодек.latin1
карты байты 0-255 для символов Юникода 0-255, который является изящным.Кодек, конечно, будет кодировать ваши персонажи - 128-255 кодируется как 2 или 3 байта в UTF-8 (на удивление, средний накладные расходы - 50%, больше, чем base64!). Это довольно убивает "элегантность" отображения 1:1.
Обратите внимание, что символы Unicode 0-255 включают неприятные невидимые/управляющие символы (новая строка, формальная подача, мягкая дефис и т.д.) делая ваши двоичные данные раздражающими для просмотра в текстовых редакторах.
Учитывая эти недостатки, Я не рекомендую latin1, если только вы точно понимаете, почему вы этого хотите. Я просто упоминаю об этом как о другом "естественном" кодировании, которое на ум.