【问题标题】:Create a file if it doesn't exist, otherwise do nothing如果文件不存在则创建一个文件,否则什么也不做
【发布时间】:2020-05-29 14:37:25
【问题描述】:

我有一个我会运行多次的脚本,这个脚本的main函数的第一行是这样的:

def main():
    users_csv_file_init()

这个函数应该做的是创建一个 CSV 文件并附加列的名称,如果这样的文件不存在,如果存在,它什么也不做。我写的是这样的:

def users_csv_file_init():
    with open("users.csv", 'a+') as output_file:
        writer = csv.writer(output_file)
        writer.writerow(["userid", "username", "fname", "lname", "uuid"])

这失败了,因为每次我运行脚本时它都会创建一个新行(列的名称),这是有道理的,因为a+ 会在文件不存在时创建文件并以附加模式打开它。但我也不能更改为w+,因为这会删除文件中以前的所有内容。并从open()only w+ and a+ seem的模式中创建文件,如果文件不存在。

我可以手动检查文件是否存在,如下所示:

def users_csv_file_init():
    if not os.path.exists("users.csv"):
        with open("users.csv", 'w') as output_file:
            writer = csv.writer(output_file)
            writer.writerow(["userid", "username", "fname", "lname", "uuid"])

但是I'm told 这样做是不合 Python 的并且容易出现竞争条件。我怎样才能正确地做到这一点?

【问题讨论】:

  • 除非你实施一些锁,否则你总是会得到加注条件。就我而言,这是最好的方法。
  • 你应该接受 Sayse 的回答而不是我的。假设所有打开文件的脚本都这样做,它可以避免竞争条件,因为独占模式是原子的。

标签: python


【解决方案1】:

你可以抓住FileExistsError,尝试用独占创建模式打开文件。

打开独占创建,如果文件已经存在则失败

def users_csv_file_init():
    try:
        with open("users.csv", 'x') as output_file:
            writer = csv.writer(output_file)
            writer.writerow(["userid", "username", "fname", "lname", "uuid"])
    except FileExistsError:
        pass

【讨论】:

  • @Barmar - 如果以独占创建模式打开 - open docs
  • 没看到你用x,我评论的时候你编辑问题了吗?
  • @Barmar - 有轻微的比赛条件,是的,哈哈。当您发表评论时,我只是在仔细检查打开的文档并进行更新
【解决方案2】:

a模式打开文件,然后用tell()查看文件位置。如果是0,则文件已创建,为空,需要写头行。

def users_csv_file_init():
    with open("users.csv", 'a') as output_file:
        if output_file.tell() == 0:
            writer = csv.writer(output_file)
            writer.writerow(["userid", "username", "fname", "lname", "uuid"])

顺便说一句,如果您只是写入文件,则无需使用a+ 模式。 + 模式用于读取和写入同一个文件对象。

【讨论】:

  • 仅供参考,这也有竞争条件,理论上可能导致标题被写入两次。
  • @KurtisRader 是的。这就是为什么我赞成 Sayse 的回答。
【解决方案3】:

是的,It's easier to ask forgiveness than it is to get permission. 所以你不应该检查文件,而只是尝试访问它并处理异常。

现在回到你的问题。

您应该尝试读取read mode 中的文件,如果该文件不存在,则在 except 块中处理该情况。

def users_csv_file_init():
    try:
        with open("ussers.csv", 'r') as output_file:
            pass  # do nothing
    except FileNotFoundError:
        # now open again in a+ mode and do your thing
        with open("users.csv", 'a+') as output_file:
            writer = csv.writer(output_file)
            writer.writerow(["userid", "username", "fname", "lname", "uuid"])
    finally:
        pass


users_csv_file_init()

【讨论】:

  • 这与调用os.path.exists()具有相同的竞争条件
  • Barmar 是正确的,使用exists 或这种方法的问题是可以在函数调用之后但在调用打开文件写入之前创建文件到
  • @Sayse,我同意同一点,但我的代码没有 os.path.exists()。它在其他人的评论中。
猜你喜欢
  • 2021-09-13
  • 2016-06-18
  • 2012-04-08
  • 2014-01-02
  • 2011-01-19
  • 2012-05-10
  • 1970-01-01
相关资源
最近更新 更多