在pickle加载时出现"UnicodeDecodeError: 'charmap'编解码器无法解码"错误

10

我正在尝试将一组Tweet对象保存在文件中。Tweet类实例包含utf8编码字符。您可以在下面的代码中看到:

class Tweet:
    author='';
    text='';
    time='';
    date='';
    timestamp='';

with open('tweets.dat','wb') as f:
     pickle.dump(all_tweets,f)

with open('tweets.dat') as f:
   all_tweets = pickle.load(f)

当我运行代码时,pickle.load(f)这一行会返回一个异常,错误信息为:
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 25: character maps to <undefined>

我的机器规格:

Python 3.5.2 | Anaconda 4.2.0(64位)|(默认,2016年7月5日, 11:41:13)[MSC v.1900 64位(AMD64)]在win32上


为什么要以二进制模式写入文件,以文本模式读取文件? - Serge Ballesta
我想检索并使用我的对象。虽然我在这里提到了简单的情况,但Tweet类也可能包含非文本属性。 - CoderInNetwork
你在写入时替换了整个 DAT 文件,但你想要使用外部编码/解码系统。你还记得“创建此文件时使用的解码方式吗?”大多数人的回答是“不知道!”,因为哪里有 os_encodingpython encodepython decode 模式呢? - dsgdfg
1个回答

29
在Python 3中,pickle模块期望底层文件对象接受或返回字节。你在写入时正确地以二进制模式打开了文件,但在读取时却没有这样做。读取部分应该是:
with open('tweets.dat', 'rb') as f:
   all_tweets = pickle.load(f)

参考:从pickle.load(fd)文档中提取的内容:

......因此,文件可以是打开供二进制读取的磁盘文件,io.BytesIO对象或任何其他符合此接口的自定义对象。


谢谢。不幸的是,它没能正常工作。它返回另一个错误:“AttributeError: Can't get attribute 'Tweet' on”。 - CoderInNetwork
1
@CoderInNetwork:你应该编辑你的问题并添加一个[mcve]。我用稍微修改过的对象进行了测试,这个对象与你问题中当前显示的对象略有不同(使用了非ASCII数据),而且测试通过了。Pickle是一个众所周知且经过充分测试的模块,但如果我们不知道你具体如何使用它,我们将无法帮助你。 - Serge Ballesta
当使用'rb'模式进行load()时,字符串被视为字节,并且考虑到反序列化的数据大小,将这些字节转换回字符串可能会成为一个问题。 - ivan866
这个,再加上pickle.load(f, encoding='latin1')对我解决了问题。 - vefthym

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接