2013-02-13 4 views
0

Я следующий пример кода в Python программирования, и что-то confuses.Here код, который записывает простую строку в файл, а затем считывает его обратноUnicodeDecodeError с Seek() и читать()

>>> data = 'sp\xe4m'         # data to your script 
>>> data, len(data)         # 4 unicode chars, 1 nonascii 
('späm', 4) 
>>> data.encode('utf8'), len(data.encode('utf8')) # bytes written to file 
(b'sp\xc3\xa4m', 5) 
>>> f = open('test', mode='w+', encoding='utf8')  # use text mode, encoded 
>>> f.write(data) 
>>> f.flush() 
>>> f.seek(0); f.read(1)        # ascii bytes work 
's' 
>>> f.seek(2); f.read(1)        # as does 2-byte nonascii 
'ä' 
>>> data[3]           # but offset 3 is not 'm' ! 
'm' 
>>> f.seek(3); f.read(1) 
UnicodeDecodeError: 'utf8' codec can't decode byte 0xa4 in position 0: 
unexpected code byte 

Теперь, что меня смущает, почему этот UnicodeDecodeError происходит, если строка данных закодирована в utf8? Чтение с помощью руководства f.read() отлично работает, но при использовании поиска для перехода и чтения (1) появляется эта ошибка.

ответ

0

Поиск в файле перемещает указатель чтения на байт, а не на символы. Вызов .read() ожидает, что он сможет читать целые символы. Поскольку UTF-8 использует несколько байтов для любого кодового номера юникода за пределами набора символов ASCII, вы не можете просто искать середину многобайтового кодового пункта UTF-8 и ожидать, что .read() будет работать.

Кодовое обозначение U + 00a4 (символ ä) кодируется в двумя байтами, C3 и A4. В файле это означает, что теперь есть 5 байт, представляющих s, p, шестнадцатеричные байты C3 и A4, затем m.

При поиске позиции 3 вы переместили заголовок файла в байт A4, а вызов .read() завершился неудачей, так как без предшествующего C3-байта контекста недостаточно для декодирования символа. Это поднимает UnicodeDecodeError; байт A4 является неожиданным, так как это не действительная последовательность UTF-8.

Стремитесь положение 4 вместо:

>>> f.seek(3); f.read(1) 
'm' 

еще лучше, не искать вокруг в UTF-8 данных или открыть файл в двоичном режиме и декодировать вручную.

+0

Моя проблема в том, что я думал, что read() фактически читает один байт, а не персонаж, ваше объяснение имеет смысл. Спасибо! – Zed