Python中是否有与数据库的ACID(原子性、一致性、隔离性和持久性)相同安全性的文件写入函数?

4
我想知道是否有类似于数据库的ACID属性的文件写入函数。原因是,我希望确保如果断电,我的文件写入操作不会出错并损坏文件。

2
它是什么类型的文件?你能使用序列化到磁盘的SQLite数据库吗? - Ryan Ginstrom
请详细说明。您要编写哪种类型的文件,以及您希望Python脚本如何工作? - Ankit Jaiswal
可能是Python中的原子状态存储?的重复问题。 - S.Lott
我主要使用文本文件进行工作。如果可以的话,我会使用数据库,但是我正在参与一个团队项目,没有其他人希望我转换到数据库。 - Varriount
3个回答

6

根据您对文件的具体操作和平台,有几个选项:

如果您需要重复将内存中的 blob 序列化到磁盘上以保持状态(例如:dhcp 租约文件),并且您正在使用 Posix 系统,那么您可以将数据写入临时文件,然后将临时文件“重命名”为目标文件。在符合 Posix 标准的系统上,这保证是原子操作,即使文件系统是否具有日志功能也不会有影响。如果您使用的是 Windows 系统,则可以通过绑定利用名为 MoveFileTransacted 的本地函数。但是,关键概念在于,临时文件可保护您的数据,如果系统重新启动,则最坏情况是您的文件包含最后一次成功刷新数据的内容。此选项要求每次想记录更改时都必须完整地写出整个文件。对于 dhcp.leases 文件而言,这不会对性能产生太大影响,但对于较大的文件可能会更加麻烦。
如果您需要不断读写数据位,那么 sqlite3 是一个好选择——它支持查询组的原子提交,并具有自己的内部日志。值得注意的一点是,由于锁定数据库、等待数据刷新等开销,原子提交会变慢。

还有一些需要考虑的事情——如果您的文件系统是异步挂载的,写入会因为write()返回而显得完成,但实际上可能还没有刷新到磁盘上。在这种情况下,重命名可以保护您,sqlite3也可以。

如果您的文件系统是异步挂载的,可能会在数据被写入之前就将其移动。因此,如果您使用的是Unix系统,则最安全的做法可能是挂载同步。不过这已经达到了“如果失败就会有人死亡”的程度。但如果它是一个嵌入式系统,并且它崩溃了,“如果失败就可能失去工作”也是为额外保护提供合理解释的好理由。


1

ZODB 是一个符合 ACID 标准的数据库存储,主要使用 Python 编写,所以从某种意义上来说答案是肯定的。但我可以想象这可能有点过度杀伤力 :)

要么操作系统为您提供此功能,要么您需要实现自己的 ACID 合规性。例如,通过在编写的文件中定义“记录”,并在打开/读取时验证已写入哪些记录(这可能意味着您需要丢弃一些未完全写入的数据)。例如,ZODB 通过在记录结尾处写入记录本身的大小来实现此目的;如果您可以读取此大小并且匹配,则知道记录已完全写入。

当然,您始终需要追加记录而不是重写整个文件。


1

在我看来,你的主要目标是确保在断电和系统崩溃的情况下文件的完整性。在这样做时有几个要考虑的事项:

  • 确保在关闭文件时将数据写入磁盘。即使你关闭了文件,一些数据可能会在操作系统缓存中等待几秒钟才被写入磁盘。你可以使用f.flush()强制将数据写入磁盘,然后使用os.fsync(f.fileno())
  • 在确定更新的数据已经安全地写入磁盘之前,不要修改现有数据。这部分可能相当棘手(并且依赖于操作系统/文件系统)。
  • 使用能够帮助你验证数据完整性的文件格式(例如使用校验和)。

另一种选择是使用sqlite3。

关于我的第二点,我强烈推荐这个演示文稿:http://www.flamingspork.com/talks/2007/06/eat_my_data.odp。它还涵盖了“原子重命名”问题。


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