假设我使用了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)
为什么第二个代码不起作用?有没有办法更新文件内容而无需打开文件两次?
答案 0 :(得分:1)
如果您确实需要使用相同的文件读取和编写pickle数据,最好单独执行,一次使用'r'
,然后使用'w'
模式。 “打开文件”的行为并不像读取或写入文件那么昂贵。打开文件,即获取文件句柄,速度相当快。
如果您担心正在读取/写入'r+b'
模式的数据大小,RAM中的大小更像是读/写的问题。您没有跳过该步骤的时间,cpu周期或磁盘操作。
还有可读性。考虑原始版本'rb'
和'wb'
(4行,易于理解)与“在一个块中执行”方法中的6。明确的seek(0)
和truncate()
无论如何都会在单独的'wb'
块中发生。也可能影响性能。单块方法没有任何好处,读取和写入容易出错 - 需要3次编辑才能修复单块方法创建的问题。 : - /
正如@glibdud在评论中提到的,在你做pickle.load()
之后,文件指针就会移动到最后。
如果要使用'r+b'
模式将数据写回文件,请使用ofile.seek()
修改光标的位置。在这种情况下,放置ofile.seek(0)
会将光标移回文件的开头。
>>> 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
>>>
@ user2357112关于截断文件的评论:我认为不需要。我腌制了一个较长的文本然后让它只写了一个int,它似乎已经被正确覆盖了。也许转储文件需要更大才能验证是否存在问题;或协议0的ascii格式对协议的二进制格式> = 1敏感。 更正:额外数据仍在文件中,如评论中所述。所以需要file.truncate()
。见下面的评论。幸运的是,在默认用法(无参数)中,它会截断到当前位置。