【问题标题】:Appropriate way to working with files? [duplicate]处理文件的适当方式? [复制]
【发布时间】:2015-03-16 01:44:28
【问题描述】:

我正在阅读 Zed Shaw 关于 Python 的书。

有一个练习要求以最少的行数实现从一个文件到另一个文件的复制。我是在一行中完成的,这里是:

 (open(argv[2], 'w')).write(open(argv[1]).read())

我的问题是,如果我这样做会发生什么最糟糕的事情?我的意思是不关闭它们。

我用另一种方式做了同样的事情,教程说这是更强大的方法。你怎么看?

with open(argv[1], 'r') as source:
   with open(argv[2], 'w') as dest:
       dest.write(source.read())

我是新人,这种问题可能看起来很傻,但对我来说很重要。

感谢您的关注。尼克

【问题讨论】:

  • 我猜如果你关心的只是阅读,那么如果你不关闭它就不会发生任何不好的事情,因为它会在你结束解释器后关闭。如果您对写作感兴趣,那么不关闭可能会很糟糕。

标签: python python-2.7


【解决方案1】:

在大多数当前的 Python 实现中,实际上,一旦文件对象被取消引用,文件就会关闭,因为垃圾收集主要是通过引用计数。

但是,Python 语言 不保证:您依赖于实现细节。

因此,单线将打破当前或未来使用更高级垃圾收集技术(例如将 GC 委托给底层 JVM 或 .Net 运行时)的 Python 实现。

with 确实保证在块退出时立即关闭——在任何正确的语言实现中。因此,它肯定更加健壮和防错。

此外,假设argv[2] 命名的文件存在,但arg[1] 命名的文件不存在。单线:

(open(argv[2], 'w')).write(open(argv[1]).read())

首先打开要写入的文件(从而清除其内容)——顺便说一句,带有多余的括号,但它们是无害的:-)。 然后在您尝试打开要读取的文件时,遇到异常并失败 - 但您打开的第一个文件无论如何都会不可挽回地消失(即磁盘上留空)。在这种情况下,这不太可能是期望的行为。

with 变体中,您首先尝试打开要读取的文件——如果失败,您永远不会清除要写入的文件。这对我来说也是一种更强大的行为——这适用于任何版本的 Python,过去、现在或未来:-)。

还有一件事:我想知道规范是否断言文件内容适合内存。如果他们不这样做,尝试一次读取文件将失败并出现内存错误——相反,您需要一个循环读取和写入一些大但有界的BUFFER_SIZE 字节。这强调了出于复制目的,最好以二进制而不是文本模式打开文件(文本模式是默认模式,因此它在您的代码中使用,因为您没有另外指定)。在这种情况下,更稳健的是:

with open(argv[1], 'rb') as source:
    with open(argv[2], 'wb') as dest:
        while True:
            buf = source.read(BUFFER_SIZE)
            if not buf: breal
            dest.write(buf)

有趣的是,仅仅复制一个文件就有多少小细节会出错,嗯?-) 这就是为什么 Python 幸福的关键是学习 Python 的大型 标准库,其中充满了精心编码的模块即使在最简单的任务中也能处理所有可能出现的各种极端情况。

这个问题的真正答案(如果我面试一个声称精通 Python 的求职者,我会给 A+)是(鼓声...):

import shutil

shutil.copy2(argv[1], argv[2])

!-) 请参阅https://docs.python.org/2/library/shutil.html#shutil.copy2 的文档(以及在同一模块中的copycopystat 函数的上方):这可以安全可靠地复制“权限位,最后访问时间,最后修改时间, 标志”...文件复制还有更多令人印象深刻的内容,shutil 会代您处理所有这些。

学习 Python 标准库至少和学习语言本身一样重要!-)

【讨论】:

  • PyPy,例如,不会在取消引用时自动关闭文件,因为它对所有内容都使用垃圾收集。我在一个非常流行的库上提交了一个错误,该库在 PyPy 上崩溃了,因为它在一个紧密的循环中执行了 open(...).read() 并且用完了文件描述符!
  • @Eevee,很好的一点:PyPy 确实是一个重要的实现(就像 IronPython / Python.Net 和 Jython 一样,它们各自的利基),它们的共同点是它们使用得更好GC 方法比 CPython 的旧引用计数支柱更接近。 GC 是关于恢复 内存 并且不应该指望它来获取其他资源,例如文件描述符!由此可见with 对保证最终确定各种资源的重要性(FD 最常见,但数据库连接、锁和无数其他资源也在那里!-)
  • 伟大而详尽的解释。非常感谢
猜你喜欢
  • 1970-01-01
  • 2012-10-30
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
  • 2013-04-28
  • 1970-01-01
  • 2011-08-25
相关资源
最近更新 更多