0

我正在关注 Programming Python 中的示例代码,但有些令人困惑。这是将简单字符串写入文件然后将其读回的代码

>>> 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

现在,让我感到困惑的是,如果数据字符串是 utf8 编码的,为什么会发生这个 UnicodeDecodeError?使用手动 f.read() 读取可以正常工作,但是当使用 seek 跳转和 read(1) 时,会出现此错误。

4

1 回答 1

2

在文件中查找将按字节移动读取指针,而不是按字符。该.read()调用希望能够读取整个字符。因为 UTF-8 对 ASCII 字符集之外的任何 unicode 代码点使用多个字节,所以您不能只寻找多字节 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 数据中四处寻找,或者以二进制模式打开文件并手动解码。

于 2013-02-13T10:11:45.180 回答