如果文件在Python中不存在,则以原子方式创建文件

时间:2015-10-19 20:44:35

标签: python atomicity

我正在寻找以下原子版:

import os

def tryMakeFile(filename):
    try:
        with open(filename) as _:
            return False
    except FileNotFoundError:
        with open(filename, mode='a') as _:
            return True

(请不要在这里评论风格问题 - 我知道这段代码在很多方面都很糟糕,但它足以说明我的问题。)

换句话说,我正在寻找一种方法来检查文件是否存在,如果没有,则在Python中创建它,以便我知道发生了哪种情况。但是这样做的方式是在多个进程之间没有竞争条件(在我给出的示例代码中,两个进程都可以认为他们创建了文件,如果第二个进程运行而第一个进程在第一个和第二个进程之间被挂起呼叫)。

或者,换句话说,我正在寻找与Java Files.createFile调用相当的Python。

编辑:请注意,当我说“Python”时,我的意思是“便携式Python”。说“使用这个库*(*这个库只在Windows上可用,或者不在Windows上,或者仅在蓝月亮后的第二个星期二)”并不是我想要的。我正在寻找明确原子的东西,标准库和/或内置的一部分,并且它可以在通用平台上使用。

3 个答案:

答案 0 :(得分:9)

您可以将os.openos.O_CREAT | os.O_EXCL flags一起使用,如果该文件存在则会失败,它们是根据Unix和Windows上提供的文档 但是我我不确定Windows上是否存在原子文件创建:

os.open("filename", os.O_CREAT | os.O_EXCL)

来自linux open man page

  

O_EXCL   如果设置了O_CREAT和O_EXCL,则如果文件存在,open()将失败。检查文件是否存在以及文件的创建(如果不存在)对于执行open()的其他线程应该是原子的,在O_EXCL和O_CREAT设置的同一目录中命名相同的文件名。如果设置了O_EXCL和O_CREAT,并且路径名称为符号链接,则open()将失败并将errno设置为[EEXIST],而不管符号链接的内容如何。如果设置了O_EXCL且未设置O_CREAT,则结果未定义。

如果文件存在,您不确定要执行的操作,但只需在文件已存在时捕获FileExistsError

import os

def try_make_file(filename):
    try:
        os.open(filename,  os.O_CREAT | os.O_EXCL)
        return True
    except FileExistsError:
        return False

答案 1 :(得分:8)

如果您使用的是Python 3.3或更高版本,则可以将{x'模式与open()一起使用:

  

'x'打开以进行独占创建,如果文件已存在则失败

<?php
include '@ConnectDB.php' ;
include './includes/PHPReport.php';


        $inCucode   = "GLLL01";               
        $inProdCode =  "71MRT18818W";   
        $inBuyNum    = "NONS01"; 

        // Prepare Stored Procedure call //
        $proc = 'CALL WLKLIB.DSH3518SQ(?,?,?)';
        $stmt = db2_prepare($conn, $proc) or die("db2_prepare failed " . db2_stmt_error(). " and " .db2_stmt_errormsg());
        db2_bind_param($stmt, 1, 'inCucode', DB2_PARAM_IN,DB2_CHAR);
        db2_bind_param($stmt, 2, 'inProdCode', DB2_PARAM_IN,DB2_CHAR);
        db2_bind_param($stmt, 3, 'inBuyNum', DB2_PARAM_IN,DB2_CHAR);
        db2_execute($stmt);
        while (db2_fetch_row($stmt)) {
            $Fld2 =  db2_result($stmt, 1);
            $Fld1  = db2_result($stmt, 0);
            $Fld3 =  db2_result($stmt, 2);
            $Fld4 =  db2_result($stmt, 3);
            $Fld5 =  db2_result($stmt, 4);
            $Fld6 =  db2_result($stmt, 5);
            $Fld7 =  db2_result($stmt, 6);
            $Fld8 =  db2_result($stmt, 7);
            $Fld9 =  db2_result($stmt, 8);
            $Fld10 =  db2_result($stmt, 9);
            $Fld11 =  db2_result($stmt, 10);
            $Fld12 =  db2_result($stmt, 11);
            $Fld13 =  db2_result($stmt, 12);

            //Create new PHPReport object
            $R=new PHPReport();

            $R->load(array(
                'id'=>'product',
                'header'=>array(
                    'SKU','Customer Code','Discontinued', 'Available Quantity','Lead Time','Last Order Quanity','Daily Demand','Days on Hand','PO Last Issued Date','PO Quantity','Price','Product Description','Company Code'
              ),

               'config'=>array(
                   0=>array('width'=>120,'align'=>'right'),
                   1=>array('width'=>100,'align'=>'left'),
                   2=>array('width'=>120,'align'=>'left'),
                   3=>array('width'=>120,'align'=>'left'),
                   4=>array('width'=>120,'align'=>'left'),
                   5=>array('width'=>120,'align'=>'left'),
                   6=>array('width'=>120,'align'=>'left'),
                   7=>array('width'=>120,'align'=>'left'),
                   8=>array('width'=>120,'align'=>'left'),
                   9=>array('width'=>120,'align'=>'left'),
                   10=>array('width'=>120,'align'=>'left'),
                   11=>array('width'=>200,'align'=>'left'),
                   12=>array('width'=>120,'align'=>'left'),
                   ),
                'data'=>array(
                    array($Fld2),
                    array($Fld1),
                    array($Fld3),
                    array($Fld4),
                    array($Fld5),
                    array($Fld6),
                    array($Fld7),
                    array($Fld8),
                    array($Fld9),
                    array($Fld10),
                    array($Fld11),
                    array($Fld12),
                    array($Fld13)
                ),
            )

          );
            echo $R->render();
            exit();
        }
  ?>

答案 2 :(得分:1)

使用pathlib.Path还有另一种形式:

from pathlib import Path

def try_make_file(filename):
    try:
        Path(filename).touch(exist_ok=False)
        return True
    except FileExistsError:
        return False

它没有明确记录,但是在源代码中我们可以看到这暗示着os.O_EXCL标志:

if not exist_ok:
    flags |= os.O_EXCL

请参见the function definition in the pathlib source code

因此,它具有与其他解决方案相同的属性(即,尚不清楚在Windows上是否可以使用此功能)。