是否需要关闭没有引用它们的文件?

时间:2016-03-16 20:20:26

标签: python python-2.7 file

作为编程的完全初学者,我试图理解打开和关闭文件的基本概念。我正在做的一个练习是创建一个脚本,允许我将内容从一个文件复制到另一个文件。

in_file = open(from_file)
indata = in_file.read()

out_file = open(to_file, 'w')
out_file.write(indata)

out_file.close()
in_file.close()

我试图缩短这段代码并提出这个问题:

indata = open(from_file).read()
open(to_file, 'w').write(indata)

这对我有效并且看起来更有效率。然而,这也是我感到困惑的地方。我想我遗漏了对打开文件的引用;不需要in_file和out_file变量。但是,这是否会让我留下两个打开的文件,但没有任何文件可以引用它们?我如何关闭这些,或者是否需要关闭?

非常感谢任何有助于阐明这一主题的帮助。

6 个答案:

答案 0 :(得分:56)

处理此问题的pythonic方法是使用with context manager

with open(from_file) as in_file, open(to_file, 'w') as out_file:
    indata = in_file.read()
    out_file.write(indata)

与这样的文件一起使用,with将确保为您完成所有必要的清理工作,即使read()write()抛出错误。

答案 1 :(得分:37)

你问过“基本概念”,所以让我们从顶部开始:当你打开文件时,你的程序可以访问系统资源,即访问程序之外的东西自己的记忆空间。这基本上是操作系统提供的一些魔力(系统调用,在Unix术语中)。隐藏在文件对象内部是对“文件描述符”的引用,“文件描述符”是与打开文件关联的实际OS资源。关闭文件会告诉系统释放此资源。

作为操作系统资源,进程可以保持打开的文件数量有限:很久以前,Unix上的每进程限制大约为20。现在我的OS X盒子限制了256个打开的文件(虽然这是一个强制限制,可以提出)。其他系统可能会设置a few thousandtens of thousands的限制(每个用户,在这种情况下不是每个进程)。程序结束后,所有资源都会自动释放。因此,如果您的程序打开一些文件,对它们执行某些操作并退出,您可能会马虎虎虎,您永远不会知道其中的区别。但是,如果您的程序将打开数千个文件,那么您最好发布打开的文件以避免超出操作系统限制。

在进程退出之前关闭文件还有另一个好处:如果打开文件进行写入,关闭它将首先“刷新其输出缓冲区”。这意味着i / o库优化磁盘使用通过收集(“缓冲”)您写出的内容,并将其分批保存到磁盘。如果您将文本写入文件并立即尝试重新打开并阅读它而不先关闭输出句柄,您会发现并非所有内容都已写出来。此外,如果您的程序过于突然关闭(有信号,或偶尔甚至通过正常退出),输出可能永远不会被刷新。

关于如何发布文件已经有很多其他答案,所以这里只是一个简短的方法列表:

  1. 明确地使用close()。 (注意python新手:不要忘记parens!我的学生喜欢写in_file.close,什么也不做。)

  2. 推荐:隐含地,通过使用with语句打开文件。当close()块结束时,即使异常终止(来自异常),也会调用with方法。

    with open("data.txt") as in_file:
        data = in_file.read()
    
  3. 引用管理器或垃圾收集器隐式地,如果您的python引擎实现它。不建议这样做,因为它不是完全便携的;请参阅其他答案了解详情。这就是with语句被添加到python的原因。

  4. 隐含地,当你的程序结束时。如果文件打开输出,则可能会在将所有内容刷新到磁盘之前存在程序退出的风险。

答案 2 :(得分:35)

默认的python interpeter CPython使用引用计数。这意味着一旦没有对象的引用,它就会被垃圾收集,即清理。

在你的情况下,做

open(to_file, 'w').write(indata)

将为to_file创建一个文件对象,但不会将其设置为名称 - 这意味着没有对它的引用。你不可能在这一行之后操纵对象。

CPython将检测到这一点,并在使用后清理对象。对于文件,这意味着自动关闭它。原则上,这很好,你的程序不会泄漏内存。

"问题"这个机制是CPython解释器的实现细节。语言标准明确不保证它!如果您正在使用替代解释器(如pypy),则文件的自动关闭可能会无限期地延迟。这包括其他隐式操作,例如在关闭时刷新写入。

此问题也适用于其他资源,例如网络套接字。优秀的做法是始终显式处理此类外部资源。从python 2.6开始,with语句使这个优雅:

with open(to_file, 'w') as out_file:
    out_file.write(in_data)

TLDR:它有效,但请不要这样做。

答案 3 :(得分:7)

在处理文件对象时,最好使用 with 关键字。这样做的好处是,即使在路上引发异常,文件也会在套件完成后正确关闭。它也比编写等效的try-finally块短得多:

>>> with open('workfile', 'r') as f:
...     read_data = f.read()
>>> f.closed
True

答案 4 :(得分:7)

到目前为止,在python 中工作时,答案绝对正确。您应该使用with open()上下文管理器。它是一个很棒的内置功能,可以帮助您快速完成常见的编程任务(打开和关闭文件)。

但是,由于您是初学者,因此无法访问Settings Encryption documentation  和context managers在整个职业生涯中,我将从一般编程的立场来解决这个问题。

您的代码的第一个版本非常好。您打开文件,保存引用,从文件中读取,然后关闭它。当语言没有为任务提供快捷方式时,这就是编写大量代码的方式。我唯一要改进的是将close()移动到您打开的位置并读取文件。打开并读取文件后,您将内容存储在内存中,不再需要打开文件。

in_file = open(from_file)
indata = in_file.read()
out_file.close() 

out_file = open(to_file, 'w')
out_file.write(indata)
in_file.close()

答案 5 :(得分:5)

一种安全的方式来打开文件而不必担心你没有关闭它们是这样的:

with open(from_file, 'r') as in_file:
    in_data = in_file.read()

with open(to_file, 'w') as out_file:
    outfile.write(in_data)