2013-12-16 3 views
3

Я попыталсяКак открыть текстовый файл в кодировке unicode внутри zip?

with zipfile.ZipFile("5.csv.zip", "r") as zfile: 
    for name in zfile.namelist(): 
     with zfile.open(name, 'rU') as readFile: 
       line = readFile.readline() 
       print(line) 
       split = line.split('\t') 

он отвечает:

b'$0.0\t1822\t1\t1\t1\n' 
Traceback (most recent call last) 
File "zip.py", line 6 
    split = line.split('\t') 
TypeError: Type str doesn't support the buffer API 

Как открыть текстовый файл в кодировке Юникод, а не как b?

+0

Мне кажется, что zip-библиотека не поддерживает параметры кодировки для 'open'. Если это правильно, я думаю, вам придется использовать оболочку 'codecs.EncodedFile' или вручную декодировать каждую строку. –

+0

как я могу это сделать? –

+0

Знаете ли вы правильную кодировку для файла? Это похоже на utf-8 для меня, но это плохая идея угадать, если вы можете избежать этого. –

ответ

3

Редактировать Для Python 3, используя io.TextIOWrapper, как описывает Дж. Ф. Себастьян, лучший выбор. Ответ ниже может быть полезен для 2.x. Я не думаю, что что-то ниже на самом деле неверно даже для 3.x, но io.TestIOWrapper все еще лучше.

Если файл UTF-8, это будет работать:

# the rest of the code as above, then: 
with zfile.open(name, 'rU') as readFile: 
    line = readFile.readline().decode('utf8') 
    # etc 

Если вы собираетесь быть итерация над файлом, вы можете использовать codecs.iterdecode, но это не будет работать с readline().

with zfile.open(name, 'rU') as readFile: 
    for line in codecs.iterdecode(readFile, 'utf8'): 
     print line 
     # etc 

Обратите внимание, что ни один подход не является безопасным для многобайтовых кодировок. Например, малоинтенсивный UTF-16 представляет символ новой строки с байтами b'\x0A\x00'. Инструмент, не поддерживающий unicode, который ищет новые строки, будет неправильно разбит, оставив нулевые байты в следующей строке. В таком случае вам нужно будет использовать что-то, что не пытается разделить входными линиями новыми, например ZipFile.read, а затем сразу декодировать всю строку байта. Это не относится к utf-8.

+0

Я проверил и действительно '.readline(). Decode ('utf-16')' fail с исключением. Хуже того, 'codecs.iterdecode()' производит неправильный вывод молча (новые строки сдвинуты на следующую строку). ['io.TextIOWrapper()'] (http://stackoverflow.com/a/20603185/4279) позволяет избежать таких проблем. – jfs

1

Причина, по которой вы видите эту ошибку, заключается в том, что вы пытаетесь смешать байты с unicode. Аргумент split также должен быть байт-строка:

>>> line = b'$0.0\t1822\t1\t1\t1\n' 
>>> line.split(b'\t') 
[b'$0.0', b'1822', b'1', b'1', b'1\n'] 

Чтобы получить строку Юникода, используйте decode:

>>> line.decode('utf-8') 
'$0.0\t1822\t1\t1\t1\n' 
6

Чтобы преобразовать байтовый поток в поток Unicode, можно использовать io.TextIOWrapper():

encoding = 'utf-8' 
with zipfile.ZipFile("5.csv.zip") as zfile: 
    for name in zfile.namelist(): 
     with zfile.open(name) as readfile: 
      for line in io.TextIOWrapper(readfile, encoding): 
       print(repr(line)) 

Примечание: TextIOWrapper() использует универсальный режим новой строки по умолчанию. rU режим в zfile.open() устарел с версии 3.4.

Он избегает проблем с многобайтовыми кодировками, описанными в @Peter DeGlopper's answer.

+0

Да, если это работает над файловыми объектами, это, вероятно, самый безопасный ответ в тех случаях, когда вы не можете предоставить кодировку при открытии файла (или использовать метод 'codecs.open'.) Я видел рекомендацию использовать его на месте режима 'rU', но поскольку 3.4 еще не вышел, предупреждение об устаревании не представляется возможным.Разумеется, правильная обработка многострочных строк новой строки является веской причиной даже без этого - интересно, насколько это было связано с решением об осуждении? –

+0

Это действительно работает. Это * способ * сделать это в Python 3. (sys.stdin, sys.stdout, (text) pipe в модуле 'subprocess' создаются с помощью' TextIOWrapper'). 'codecs.open' ожидает имя файла (я не вижу, как это помогает с zip-файлом). 'codecs.getreader (encoding) (file_obj)' может быть полезен на Python 2. – jfs

+0

Да, я думал в общем случае - я не вижу лучшего варианта для zip-файлов. Возможно, мой комментарий будет лучше сформулирован «учитывая, что это работает над файловыми объектами ...» –

Смежные вопросы