10

我有一个 Python 程序,可以存储数据并将其写入文件。数据是原始二进制数据,内部存储为str. 我正在通过 utf-8 编解码器写出来。但是,我进入UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 25: character maps to <undefined>cp1252.py文件。

在我看来,这就像 Python 正在尝试使用默认代码页来解释数据。它没有默认代码页。这就是我使用的原因str,而不是unicode.

我想我的问题是:

  • 如何在 Python 中表示内存中的原始二进制数据?
  • 当我通过编解码器写入原始二进制数据时,如何对其进行编码/取消编码?
4

3 回答 3

22

注意:这是为 Python 2.x 编写的。不确定是否适用于 3.x。

str在内存中使用原始二进制数据是正确的。
[如果您使用的是 Python 2.6+,最好使用bytes2.6+ 中的 which 只是一个别名,str但可以更好地表达您的意图,如果有一天您将代码移植到 Python 3 会有所帮助。]

正如其他人所指出的,通过编解码器写入二进制数据很奇怪。写入编解码器采用 unicode并将字节输出到文件中。你试图倒退,因此我们对你的意图感到困惑......

[并且您对错误的诊断看起来是正确的:由于编解码器需要 unicode,因此 Python 正在使用系统的默认编码将您的 str 解码为 un​​icode,这令人窒息。]

你想在输出文件中看到什么?

  • 如果文件应按原样包含二进制数据

    那么你不能通过编解码器发送它;您必须将其直接写入文件。编解码器对所有内容进行编码,并且只能发出有效的 unicode 编码(在您的情况下,是有效的 UTF-8)。没有输入可以让它发出任意字节序列!

    • 如果你需要 UTF-8 和原始二进制数据的混合,你应该直接打开文件,并混合写入some_data with some_text.encode('utf8')...

    但是请注意,将 UTF-8 与原始任意数据混合是非常糟糕的设计,因为这样的文件处理起来非常不方便!理解 unicode 的工具会阻塞二进制数据,让您甚至无法方便地查看(更不用说修改)文件了。

  • 如果你想在 unicode 中友好地表示任意字节

    传递data.encode('base64')给编解码器。Base64 只产生干净的 ascii(字母、数字和一点标点符号),因此它可以清楚地嵌入到任何东西中,在人们看来它显然是二进制数据,而且它相当紧凑(略高于 33% 的开销)。

    PS你可能会注意到这data.encode('base64')很奇怪。

    • .encode()应该采用 unicode 但我给它一个字符串?!Python 有几个伪编解码器可以转换 str->str,例如 'base64' 和 'zlib'。

    • .encode()总是返回一个 str 但你会把它输入一个需要 unicode 的编解码器?!在这种情况下,它只会包含干净的 ascii,所以没关系。data.encode('base64').encode('utf8')如果它能让你感觉更好,你可以明确地写出来 。

  • 如果您需要从任意字节到 unicode 的 1:1 映射

    传递data.decode('latin1')给编解码器。 latin1将字节 0-255 映射到 Unicode 字符 0-255,这有点优雅。

    编解码器当然会对您的字符进行编码 - 128-255 在 UTF-8 中被编码为 2 或 3 个字节(令人惊讶的是,平均开销为 50%,超过 base64!)。这完全扼杀了 1:1 映射的“优雅”。

    另请注意,Unicode 字符 0-255 包括令人讨厌的不可见/控制字符(换行符、换页符、软连字符等),使您的二进制数据在文本编辑器中查看时很烦人。

    考虑到这些缺点,我不推荐 latin1,除非您完全了解您想要它的原因。
    我只是提到它是另一种“自然”的编码方式。

于 2010-04-11T17:23:27.547 回答
0

通常不应将编解码器与 一起使用str,除非将它们转换为unicodes。latin-1如果您认为自己想要 unicode 中的“原始”数据,也许您应该考虑使用编解码器。

于 2010-04-09T22:02:22.017 回答
0

对于您的第一个问题:在 Python 中,常规字符串(即,不是 unicode 字符串)是二进制数据。如果要写unicode字符串和二进制数据,把unicode字符串转成二进制数据放在一起:

# encode the unicode string as a string
bytes = unicodeString.encode('utf-8')
# add it to the other string
raw_data += bytes
# write it all to a file
yourFile.write(raw_data)

对于你的第二个问题:你write()的原始数据;然后,当您阅读它时,您会这样做:

import codecs
yourFile = codecs.open( "yourFileName", "r", "utf-8" )
# and now just use yourFile.read() to read it
于 2010-04-09T22:32:53.133 回答