Python';在r+的腌菜工作;b模式?

Python';在r+的腌菜工作;b模式?,python,pickle,Python,Pickle,假设我使用pickle.dump存储了一个整数值,我想通过添加1来更新该整数值。以下代码起作用: with open('../CONFIG.txt', 'rb') as ofile: value = pickle.load(ofile) with open('../CONFIG.txt', 'wb') as ofile: pickle.dump(value + 1, ofile, protocol=2) 但一旦我使用r+b模式,它就不会: with open('../CONF

假设我使用pickle.dump存储了一个整数值,我想通过添加1来更新该整数值。以下代码起作用:

with open('../CONFIG.txt', 'rb') as ofile:
    value = pickle.load(ofile)

with open('../CONFIG.txt', 'wb') as ofile:
    pickle.dump(value + 1, ofile, protocol=2)
但一旦我使用r+b模式,它就不会:

with open('../CONFIG.txt', 'r+b') as ofile:
    value = pickle.load(ofile)
    pickle.dump(value + 1, ofile, protocol=2)

为什么第二个代码不起作用?有没有办法在不打开文件两次的情况下更新文件内容

更新2: 如果确实需要使用同一个文件读取和写入pickle数据,最好分别使用
'r'
模式和
'w'
模式执行。“打开一个文件”的行为并不像读或写文件那样昂贵。打开一个文件,也就是获得一个文件句柄,相当快

如果您关心在
'r+b'
模式下读取/写入的数据的大小,则RAM中的大小比读取/写入更重要。您不会因为时间、cpu周期或磁盘操作而跳过该步骤

还有可读性。在“做一个一块”的方法中,考虑你的原始版本:<代码>“RB”<代码> >代码> > WB '/COD>(4行,易于理解)vs 6。显式的
seek(0)
truncate()
是在单独的
'wb'
块中发生的。可能也会影响性能。“一块”方法没有任何好处,读起来更糟,写起来更容易出错-需要3次编辑才能解决“一块”方法创建的问题:-/

原始答复: 正如@glibdud在注释中提到的,在执行
pickle.load()
之后,文件指针将移动到末尾

如果要使用
'r+b'
模式将数据写回文件,请使用修改光标的位置。在这种情况下,放置会将光标移回文件的开头

>>> with open('CONFIG.txt', 'r+b') as ofile:
...     value = pickle.load(ofile)
...     print value
...     # re-position the cursor to the start of the file before dumping new data
...     ofile.seek(0)
...     pickle.dump(value + 1, ofile, protocol=2)
...     # truncate anything left in the file if the prev pickled data was larger
...     ofile.truncate()
...
3
>>> 
>>> # let's read again to see
...
>>> with open('CONFIG.txt', 'r+b') as ofile:
...     value = pickle.load(ofile)
...     print value
...
4
>>>
更新1和3:
@user2357112关于截断文件的评论:我认为不需要它。我将一个较长的文本进行了pickle处理,然后让它只写一个int,它似乎已经正确地覆盖了。可能转储文件需要更大,以验证是否存在问题;或者协议0的ascii格式易受影响,而协议>=1的二进制格式易受影响。更正:额外数据仍在文件中,如注释中所述。这是必要的。见下面的评论。幸运的是,在默认用法(无参数)中,它会截断到当前位置。

您正在旧的pickle之后编写新的pickle。对于
read
write
“有没有一种方法可以在不打开两次文件的情况下更新文件内容?”--为什么不想打开两次?打开两次文件似乎是重复的。这也是一个一般性的学习问题-我想了解为什么上面的代码没有按我预期的方式工作。同样的原因是,以读/写模式打开任何文件,然后执行
read()
,然后执行
write(…)
将附加内容,而不是覆盖内容:读取(
pickle.load()
)将位置指针移到文件的末尾,写入(
pickle.dump()
)就从那里开始。这很有意义。“dump”这个词让我想到默认情况下会覆盖整个文件。谢谢然后截断文件,这样,如果新的pickle文件比旧的文件短,那么在新的pickle文件结束时就不会留下任何垃圾。有趣的是,我没有想到这一点。我以为它会完全覆盖。在我上面的编辑/更新中,它看起来确实是这样的。它加载得很好,因为pickle格式包含了一个结束pickle标记,所以从文件中取消pickle不会试图读取额外的垃圾,但它仍然存在,浪费了磁盘空间。回答得很好。你能详细解释一下为什么你认为用
rb
wb
分别读写它们更好吗。得到一个文件句柄很容易,这不是一个大问题,但我(礼貌地)对你的想法感到好奇。我想我已经回答了那个部分-没有什么是通过在一个区块中做得到的,很多都丢失了(阅读最新的编辑):考虑你的原始版本有<代码> 'Rb' < /C>和<代码> 'WB' < /Cord>(4行,易于理解)。vs 6中的“一块完成”方法。显式的
seek(0)
truncate()
是在单独的
'wb'
块中发生的。