2013-08-21 2 views
5

У меня есть огромный текстовый файл, который я хочу открыть.
Я читаю файл в кусках, избегая проблем с памятью, связанных с чтением слишком большого количества файла одновременно.UnicodeDecodeError: неожиданный конец данных

фрагмент кода:

def open_delimited(fileName, args): 

    with open(fileName, args, encoding="UTF16") as infile: 
     chunksize = 10000 
     remainder = '' 
     for chunk in iter(lambda: infile.read(chunksize), ''): 
      pieces = re.findall(r"(\d+)\s+(\d+_\d+)", remainder + chunk) 
      for piece in pieces[:-1]: 
       yield piece 
      remainder = '{} {} '.format(*pieces[-1]) 
     if remainder: 
      yield remainder 

код бросает ошибку UnicodeDecodeError: 'utf16' codec can't decode bytes in position 8190-8191: unexpected end of data.

Я пробовал UTF8 и получил ошибку UnicodeDecodeError: 'utf8' codec can't decode byte 0xff in position 0: invalid start byte.

latin-1 и iso-8859-1 поднял ошибку IndexError: list index out of range

Пробу входного файла:

b'\xff\xfe1\x000\x000\x005\x009\x00\t\x001\x000\x000\x005\x009\x00_\x009\x007\x004\x007\x001\x007\x005\x003\x001\x000\x009\x001\x00\t\x00\t\x00P\x00o\x00s\x00t\x00\t\x001\x00\t\x00H\x00a\x00p\x00p\x00y\x00 \x00B\x00i\x00r\x00t\x00h\x00d\x00a\x00y\x00\t\x002\x000\x001\x001\x00-\x000\x008\x00-\x002\x004\x00 \x00' 

я также упомянуть, что у меня есть несколько из этих огромных текстовых файлов.
UTF16 отлично подходит для многих из них и не работает в определенном файле.

В любом случае, чтобы решить эту проблему?

+0

Если ваш файл ввода * * UTF-16 (хотя и усечен), то Latin1 или UTF-8, безусловно, не будут работать. –

+0

Можем ли мы увидеть образец вашего входного файла? Тогда, по крайней мере, мы можем взять удар, угадывая используемую кодировку. Прочитайте файл как двоичный файл и распечатайте его.'print (open (fileName, 'rb'). read (120))' должен дать нам достаточно для работы. –

+0

@MartijnPieters Я добавил образец входного файла. – Presen

ответ

5

Игнорировать испорченные данные (которые могут привести к потере данных), установите errors='ignore' на open() вызова:

with open(fileName, args, encoding="UTF16", errors='ignore') as infile: 

В open() function documentation состояний:

  • 'ignore' ignores errors. Note that ignoring encoding errors can lead to data loss.

Это не означает, что вы можете восстановить из очевидное повреждение данных, которое вы испытываете.

Чтобы проиллюстрировать, представьте, что байт был отброшен или добавлен где-то в вашем файле. UTF-16 - это кодек, который использует 2 байта на символ. Если есть один байт, отсутствующий или излишний, тогда все байтовые пары, следующие за отсутствующим или дополнительным байтом, будут не совпадать.

Это может привести к проблемам, которые расшифровываются дальше по линии, а не обязательно сразу. В UTF-16 есть несколько кодовых страниц, которые являются незаконными, но обычно потому, что они используются в сочетании с другой байтовой парой; ваше исключение было выбрано для такого недопустимого кода. Но, возможно, были сотни или тысячи байт-пар, предшествовавших этой точке, которые были действительны UTF-16, если не разборчивый текст.

+0

Я попробовал 'errors = 'ignore'' и получил' остаток =' {} {} '.format (* pieces [-1]) IndexError: индекс индекса вне диапазона – Presen

+0

Правильно, потому что теперь вы, по-видимому, заканчиваете с помощью chunk, где 're.findall()' возвращает * нет совпадений *. Это риск игнорирования недопустимых символов; если в вашем файле отсутствует * один * байт, тогда декодирование UTF-16 может быть нечитаемым; он фактически не обнаруживается * то, что * байт отсутствует в этом случае, и исключение, которое вы видели, могло бы быть значительно хуже повреждения файла. –

3

я делал то же самое (чтение много больших текстовых файлов на куски) и побежал в ту же ошибку с одним файлы:

Traceback (most recent call last): 
    File "wordcount.py", line 128, in <module> 
    decodedtext = rawtext.decode('utf8') 
    File "/usr/lib/python2.7/encodings/utf_8.py", line 16, in decode 
    return codecs.utf_8_decode(input, errors, True) 
UnicodeDecodeError: 'utf8' codec can't decode byte 0xc2 in position 9999999: unexpected end of data 

Вот что я нашел: проблема была конкретная последовательность Unicode (\xc2\xa0\xc2\xa0) охватывающий два куска. Таким образом, эта последовательность была разделена и становилась недекодируемой. Вот как я ее решил:

# read text 
rawtext = file.read(chunksize) 

# fix splited end 
if chunknumber < totalchunks: 
    while rawtext[-1] != ' ': 
     rawtext = rawtext + file.read(1) 

# decode text 
decodedtext = rawtext.decode('utf8') 

Это также решает более общую проблему слов будучи разрезать пополам, когда они охватывают два куска.