Почему file.tell() влияет на кодировку?
Призвание tell()
при чтении моего файла в кодировке GBK вызывает следующий вызов readline()
поднять UnicodeDecodeError
, Однако, если я не позвоню tell()
, это не вызывает эту ошибку.
C: \ tmp> hexdump badtell.txt
000000: 61 20 6B 0D 0A D2 BB B0-E3 a k......
C: \ tmp> тип test.py
with open(r'c:\tmp\badtell.txt', "r", encoding='gbk') as f:
while True:
pos = f.tell()
line = f.readline();
if not line: break
print(line)
C: \ tmp> python test.py
a k
Traceback (most recent call last):
File "test.py", line 4, in <module>
line = f.readline();
UnicodeDecodeError: 'gbk' codec can't decode byte 0xd2 in position 0: incomplete multibyte sequence
Когда я удаляю f.tell()
Заявление, оно успешно расшифровано. Зачем? Я пробовал Python3.4/3.5 x64 на Win7/Win10, это все то же самое.
Любая, любая идея? Должен ли я сообщить об ошибке?
У меня большой текстовый файл, и я действительно хочу получить диапазоны позиций файла этого большого текста, есть ли обходной путь?
2 ответа
ОК, есть обходной путь, он работает до сих пор:
with open(r'c:\tmp\badtell.txt', "rb") as f:
while True:
pos = f.tell()
line = f.readline();
if not line: break
line = line.decode("gbk").strip('\n')
print(line)
Я отправил вопрос вчера здесь: http://bugs.python.org/issue26990
до сих пор нет ответа
Я только что повторил это на Python 3.4 x64 на Linux. Глядя на документы для TextIOBase
Я не вижу ничего, что говорит tell()
вызывает проблемы с чтением файла, так что, возможно, это действительно ошибка.
b'\xd2'.decode('gbk')
выдает ошибку, подобную той, которую вы видели, но в вашем файле за байтом следует байт BB
, а также
b'\xd2\xbb'.decode('gbk')
дает значение, равное '\u4e00'
не ошибка.
Я нашел обходной путь, который работает для данных в исходном вопросе, но не для других данных, как вы с тех пор нашли. Хотел бы я знать почему! я звонил seek()
после каждого tell()
со значением, которое tell()
вернулся:
pos = f.tell()
f.seek(pos)
line = f.readline()
Альтернатива f.seek(f.tell())
это использовать SEEK_CUR
режим seek()
дать позицию. Со смещением 0 это делает то же самое, что и код выше: перемещается в текущую позицию и получает эту позицию.
pos = f.seek(0, io.SEEK_CUR)
line = f.readline()