11
10
2012
8

如何更安全地覆写数据文件

本文来自依云's Blog,转载请注明。

经常地,程序在开始执行某项任务需要从文件读取数据。在任务完成后数据得到更新,新的数据会覆写到之前读取的文件中。怎么将数据写回到文件呢?一个直觉的方案是:

with open(datafile, 'w') as f:
  f.write(data)

在通常情况下,它能够正确地完成写回数据的任务。如果出于某种原因文件打开失败,通常也不会有人忘记处理。但是,当写入操作失败了呢?

时不时地编译程序看到 gcc 大把地警告:

警告:忽略声明有 warn_unused_result 属性的‘write’的返回值 [-Wunused-result]

在 Python 中,写文件时如果失败会抛出异常,上层的异常处理机制似乎能够作出相应的应对。但是,真的尽力了吗?

我也曾以为这样不会出问题。直到有一天,本地信箱里出现了这样的错误信息:

OSError: [Errno 28] No space left on device

可能是由于内核的某个 bug,我本来就所剩无几的 /home 分区没空闲空间了。一个 cronjob 在写回数据时发生异常。于是,新的数据没能写入文件。那旧数据呢?因为是以「写」方式打开文件,所以它也没了……

在那次事件之后,那段写回数据的代码变成了这个样子:

with open(datafile + '.tmp', 'w') as f:
  f.write(t)
# if the above write failed (because disk is full), the old data should be kept
os.rename(datafile + '.tmp', datafile)

注意:测试表明不使用with或者显式地关闭文件的做法是有问题的,即使在 CPython 中。

try:
  open('/dev/full', 'w').write('abc')
except:
  print('fine.')

在 Python 2.7 中会打印错误信息,Python 3.3.0 中无任何信息。都没有预料中的异常被捕获。

>>> python t.py
>>> python2 t.py
close failed in file object destructor:
IOError: [Errno 28] No space left on device

今天之所以写这个,是因为 Arch Linux CN 的群服务器遇到磁盘配额用尽的问题。XMPP 服务器 Prosody 在写入联系人信息时只写了一小部分,大部分数据丢失。这里有 bug 报告

2013年7月21日更新:Sublime Text 2 作为商业软件,竟然不仅不采用「新建+重命名」的方式写入文件,而且连写入是否成功都不检查。难怪 Linux 版中文输入法的问题迟迟不修复,原来连造成用户数据丢失的问题都无所谓

Category: 编程 | Tags: python prosody | Read Count: 13011
陆仁贾 说:
Nov 10, 2012 02:24:34 PM

现在数据恢复了么?

Avatar_small
依云 说:
Nov 10, 2012 03:16:27 PM

能恢复的部分已经恢复,剩下的没办法了。唉……

maplebeats 说:
Nov 11, 2012 11:43:41 PM

No space left on device这个错误,有前天也遇到了!!!不过还好是在我用abs的时候。。。

xanpeng 说:
Nov 23, 2012 11:46:55 AM

我的理解: 对于小文件(配置文件之类的),貌似靠谱+通用的做法就是写备份文件吧。但是大文件,备份就不可行了,这时靠谱+通用的做法是判断返回值来确定写是否成功。至于要不要做其他控制,就要实际需要吧。

Avatar_small
依云 说:
Nov 23, 2012 12:55:38 PM

和文件大小无关,取决于文件的使用方式。如果修改是 in-place 的话,当然不做备份了(所以很多数据库异常关闭后都需要自动或手动的 repair)。仅判断返回值还不够,因为你不一定有机会判断返回值(比如掉电或者内核崩溃)(所以有日志神马的,CouchDB 直接就放弃改写只追加了)。

xanpeng 说:
Nov 23, 2012 02:19:04 PM

恩。我常接触的是配置文件写,是通过备份做的,并立即flush。其他文件写,我只是判断返回值了,因为不是必要数据(比如数据库之类的),所以没做其他工作了,反正不会搞垮fs(一般都用了jbd2)。

zz 说:
Jul 13, 2013 05:32:36 PM

为何你的硬盘总是这么捉急

Star Brilliant 说:
Jul 13, 2013 05:37:10 PM

我的群也遇到了一模一样的问题,低端VPS硬盘只有10G,幸好没有数据丢失。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

| Theme: Aeros 2.0 by TheBuckmaker.com