打开文件进行读写,如有需要则创建文件。

9
什么是最优雅的打开文件的方式,使得:
  • 如果文件不存在,则创建该文件,
  • 如果文件存在,则不会被截断,
  • 可以写入文件的任何部分(通过寻址),而不仅仅是文件末尾?
就我所知,内置的open似乎无法胜任:它提供了各种模式,但我尝试过的每个模式都不能满足我的要求:
  • r+ 如果文件不存在则失败。
  • w+ 会截断文件,丢失任何现有内容。
  • a+ 将强制所有写入到文件的末尾,在我的OS X上至少如此。
在打开文件之前检查其是否存在感觉不好,因为这留下了竞态条件的空间。在异常处理程序中使用不同的模式重试打开也是一样。我希望有更好的方法。

如果你的目标是写入文件的中间位置,我怀疑没有非常干净的方法。 - msvalkon
4个回答

9

您需要使用os.open()在操作系统中比open()更低的级别上打开它。特别是,将os.RDWR | os.O_CREAT作为flags传递应该可以实现您想要的功能。有关详细信息,请参见open(2)手册页。然后,您可以将返回的FD传递给os.fdopen()以从中获取文件对象。


1
特别是与os.fdopen结合使用,这看起来非常不错。我在相关链接中找到了这个答案,它提出了相同的建议。谢谢! - MvG
1
我尝试使用 fd = os.open('.pree_config', os.O_RDWR | os.O_CREAT) config_file = os.fdopen(fd),但是出现了 io.UnsupportedOperation: not writable 错误。我通过向 os.fdopen() 传递 'r+' 参数来解决了这个问题... - deed02392

2
如果你正在使用Python 3.3+版本,你可以使用x模式(独占创建模式):
try:
    f = open('/path/to/file', 'x+')
except FileExistsError:
    f = open('/path/to/file', 'r+')

如果文件已经存在,它会引发FileExistsError错误。


0

我可能错了,但是如果没有多个线程,并且tryexcept块是同一个线程,那么不会出现竞争条件吧?(实际上可以使用多个线程吗?)

这应该能胜任。

>>>try: 
      f=open('myfile.txt','r')
   except OSError:
      f=open('myfile.txt','w')
   finally:
      #whatever file I/O you need.

我担心有多个应用程序,可能使用不同的代码。 - MvG
“同样适用于在异常处理程序中使用不同模式重试打开。”而竞争条件可能会发生在其他程序中,无论Python脚本中是否使用线程。 - Ignacio Vazquez-Abrams
@IgnacioVazquez-Abrams,我不明白,其他程序正在尝试访问该文件?那么检查应该在那个程序中进行,而不是在Python脚本中进行吧?我可能会错过一些非常明显的东西。 - Guy
@IgnacioVazquez-Abrams 无论如何,你的回答似乎已经涵盖了它。+1 - Guy
1
攻击者可以利用open()调用之间的短暂时间,尝试利用漏洞链接到系统文件并在此过程中摧毁它。 - Ignacio Vazquez-Abrams
@IgnacioVazquez-Abrams 哦。我通常不会考虑有意恶意的用户,我想我是天真的。还要检查falsetru的解决方案。看起来不错。 - Guy

0

当我尝试将项目作为字典转储到文件中时,遇到了类似的问题。然而,我导入了json,http://docs.python.org/2/library/json.html看看这个,可能非常有帮助。记得导入json。这将提供在需要时转储和加载数据的基础。在这种情况下,我正在将信息转储和加载到一个空字典中。当您想要使用空字典时,try和except方法非常有用。我发现"r+"最有用,因为它会读取和写入文件。

def dump_data():
    j = json.dumps(file.text, indent=4)
    with open("database.txt", "w") as f:
        f.write(j)

def load_data():
    try:
        with open("file.txt", "r+") as f:
            return json.load(fp=f)
    except IOError:
            return {}

现在我正在响应交互活动编写项目,并在每次写入后将修改刷新到磁盘,以防止严重崩溃或停电时丢失任何内容。在此设置中,每次修改后重新编写整个数据感觉相当低效。 - MvG

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