打开外部文件会在读取模式下产生错误或创建

时间:2012-11-11 21:27:33

标签: python file external ioerror

昨晚我编写了一个程序,将所有注释行从文件中提取出来并输出到新文件中。这是我们在编程课中经常要做的事情,通过复制和粘贴文件的选择变得非常快。

我检查输入文件和输出文件是否存在。如果输入文件确实存在,则继续执行所有操作 - 如果不存在,则请求另一个文件名。如果输出文件确实存在,请询问用户是否要覆盖 - 如果不存在,则继续执行。

我遇到的问题是,当file = open(fileName,'r')找不到文件时,一次检查正确抛出IOError,另一次检查创建一个空文件而不是给出IOError。

由于两位代码几乎完全相同,因此特别令人困惑。相同的过程,只是不同的文件名变量...

代码如下。第二部分是创建空白文件的部分。首先给出预期的错误。

# Try to open the input file
inFileOpen = False
while not inFileOpen and userTrying:
    # If it opens, all good
    try:
        inFile = open(inFileName, 'r')
        inFileOpen = True
    # If it doesn't open, ask user to try a different file
    except IOError:
        ...

# Try to open the output file
toFileOpen = False
while not toFileOpen and userTrying:
    # If the file opens in r mode, that means it exists already, so ask user if they
    # want to overwrite the existing file, if not ask for a new file name
    try:
        # ********************
        # For some reason, 'r' mode is creating a file... no clue...
        # ********************
        toFile = open(toFileName)
        toFile.close() # I have tried removing this just guessing at solutions. Didn't work.

        # ... Ask if user wants to overwrite

    # If the file can't be opened, all good, that means it doesn't exist yet
    except IOError:
        toFileOpen = False
        toFile = open(toFileName, 'w')

2 个答案:

答案 0 :(得分:2)

如果您使用的是Python 3.3,open的“x”模式与“w”相同,只是如果该文件已存在则会引发FileExistsException。这比单独的检查更好,因为它是在存在的文件的测试和打开它以进行写入之间的原子和免疫竞争条件。虽然这可能不是您当前脚本的问题,但在更安全的关键程序中可能很重要。

在旧版本的Python(2.x和3.0-3.2)中,它有点棘手。一种选择是打开文件以追加(“a”模式),然后检查当前流位置(使用tell)以查看它是否已包含某些内容。如果确实如此,但是用户想要替换旧内容,则可以调用truncate()然后seek(0)来删除当前数据并返回文件的开头。这可能仍然可能会在没有通知的情况下覆盖零长度文件,但我怀疑这不是一个大问题。另一种方法是将os.O_EXCL|os.O_CREAT标志显式传递给os.open,然后将返回的文件描述符传递给os.fdopen以获取常规Python文件对象。这基本上就是“x”模式在幕后的作用。

编辑:这是一个漂亮的上下文管理器解决方案,用于创建一个合适的get_filenameconfirm_overwrite函数来创建输出文件,这些函数可以与用户进行实际交互。此代码适用于Python 3.3,但open调用和except语句可以修改,以使其适用于早期版本。

from contextlib import contextmanager

@contextmanager
def create_output_file():
    while True:
        out_filename = get_filename()

        try:
            with open(out_filename, "x") as f:
                yield f
            break

        except FileExistsException:
            if confirm_overwrite(out_filename):
                with open(out_filename, "w") as f:
                    yield f
                break

将其与with声明一起使用:

with create_output_file() as f:
    f.write("whatever")

答案 1 :(得分:1)

我认为os.path.exists(filename)是检查文件的好方法:

例如

 while not os.path.exists(infile):
     infile = askfilename()
 with open(infile) as f:
     for line in f:
         ...

你可以为outfile做类似的事情