标题可能会更好,但无论如何。我想知道是否有任何函数可以写入文件,就像数据库的 ACID 属性一样。原因是,我想确保我正在执行的文件写入不会在断电时弄乱和损坏文件。
3 回答
根据您对文件和平台所做的具体操作,有几个选项:
如果您将 blob 从内存重复序列化到磁盘以保持状态(例如:dhcp 租用文件),如果您在 Posix 系统上,则可以将数据写入临时文件并将临时文件“重命名”为目标. 在符合 Posix 的系统上,这保证是原子操作,甚至文件系统是否被记录都无关紧要。如果您使用的是 Windows 系统,则有一个名为MoveFileTransacted的本机函数您可能可以通过绑定使用。但这里的关键概念是,临时文件保护您的数据,如果系统重新启动,最坏的情况是您的文件包含最后一次良好刷新的数据。此选项要求您在每次想要记录更改时写出整个文件。对于 dhcp.leases 文件,这不会对性能造成很大影响,但较大的文件可能会更麻烦。
如果你不断地读写数据,那么 sqlite3 是最好的选择——它支持查询组的原子提交,并拥有自己的内部日志。这里要注意的一件事是,由于锁定数据库、等待数据刷新等的开销,原子提交会更慢。
A couple other things to consider -- if your filesystem is mounted async, writes will appear to be complete because the write() returns, but it might not be flushed to disk yet. Rename protects you in this case, sqlite3 does as well.
If your filesystem is mounted async, it might be possible to write data and move it before the data is written. So if you're on a unix system it might be safest to mount sync. That's on the level of 'people might die if this fails' paranoia though. But if it's an embedded system and it dies 'I might lose my job if this fails' is also a good rationalization for the extra protection.
ZODB是用(主要)python 编写的符合 ACID 的数据库存储,所以从某种意义上说,答案是肯定的。但我可以想象这有点矫枉过正:)
操作系统必须为您提供此功能,或者您需要实现自己的 ACID 合规性。例如,通过在您写入的文件中定义“记录”,并在打开/读取时验证已写入哪些记录(这可能意味着您需要丢弃一些未完全写入的数据)。例如,ZODB 通过写入记录本身的大小来结束记录来实现这一点。如果您可以读取此大小并且匹配,则您知道记录已完全写入。
而且,当然,您总是需要附加记录而不是重写整个文件。
在我看来,您的主要目标是确保在电源故障和系统崩溃的情况下写入文件的完整性。执行此操作时需要考虑几件事:
- 确保在关闭文件时将数据写入磁盘。即使你关闭它,一些数据可能会在操作系统缓存中等待几秒钟等待写入磁盘。您可以使用 f.flush() 强制写入磁盘,然后使用 os.fsync(f.fileno())。
- 在确定更新的数据安全地保存在磁盘上之前,不要修改现有数据。这部分可能非常棘手(并且取决于操作系统/文件系统)。
- 使用有助于验证数据完整性的文件格式(例如使用校验和)。
另一种选择是使用 sqlite3。
编辑:关于我的第二点,我强烈推荐这个演示文稿:http ://www.flamingspork.com/talks/2007/06/eat_my_data.odp 。这也涵盖了“原子重命名”的问题。