我有一个Python程序,用于存储数据并将数据写入文件。数据是原始二进制数据,内部存储为str
。我是通过utf-8编解码器写出来的。但是,我在UnicodeDecodeError: 'charmap' codec can't decode byte 0x8d in position 25: character maps to <undefined>
文件中获得cp1252.py
。
这让我觉得Python正在尝试使用默认代码页来解释数据。但它没有默认代码页。这就是为什么我使用的是str
,而不是unicode
。
我想我的问题是:
答案 0 :(得分:22)
注意:这是为Python 2.x编写的。不确定是否适用于3.x。
您在内存中使用str
原始二进制数据是正确的
[如果您使用的是Python 2.6+,最好使用bytes
,它在2.6+中只是str
的别名,但更好地表达了您的意图,如果有一天您将代码移植,将会有所帮助到Python 3。]
正如其他人所说,通过编解码器写二进制数据很奇怪。写入编解码器将unicode 和输出字节带入文件。你试图向后做,因此我们对你的意图感到困惑......
[并且您对错误的诊断看起来是正确的:因为编解码器需要unicode,所以Python会使用系统的默认编码将您的str解码为unicode,这会阻塞。]
您希望在输出文件中看到什么?
如果文件应包含二进制数据:
然后你不能通过编解码器发送它;你必须写它 直接到文件。编解码器编码所有内容并且只能编码 发出有效的unicode编码(在您的情况下,有效的UTF-8)。 没有任何输入你可以让它使它发出任意 字节序列!
some_data
的写入
与some_text.encode('utf8')
... 但请注意,将UTF-8与原始任意数据混合非常 糟糕的设计,因为这样的文件处理起来非常不方便 有!理解unicode的工具会阻塞二进制文件 数据,让你用不方便的方式来查看(更不用说了 修改)文件。
如果你想要一个友好的任意字节表示 的unicode 强>:
将data.encode('base64')
传递给编解码器。 Base64仅生产
干净的ascii(字母,数字和一点点标点)所以它
它可以清楚地嵌入任何东西中,它清楚地看作是人们的
二进制数据,它相当紧凑(略高于33%)
开销)。
P.S。您可能会注意到data.encode('base64')
很奇怪。
.encode()
应该采取unicode,但我给它一个
串?! Python有几个转换str-&gt; 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 ,除非
你完全理解为什么要这样。
我只是提到它是另一种“自然”编码
记住。
答案 1 :(得分:0)
您通常不应将编解码器与str
一起使用,除非将它们转换为unicode
。如果你认为你想在你的unicodes中想要“原始”数据,也许你应该考虑使用latin-1
编解码器。
答案 2 :(得分: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