python - 处理文件的正确方法?

标签 python python-2.7

我正在阅读 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语言并不能保证:您依赖于实现细节。

因此,单行代码将在当前或 future 使用更先进的垃圾收集技术(例如将 GC 委托(delegate)给底层 JVM 或 .Net 运行时)的 Python 实现中中断。

with does保证一旦 block 退出就关闭——在语言的任何正确实现中。因此,它绝对更加健壮且防错。

此外,假设以 argv[2] 命名的文件存在,但以 arg[1] 命名的文件不存在。在一行中:

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

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

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

还有一件事:我想知道规范是否断言文件内容适合内存。如果不这样做,尝试一口气读取文件将失败并出现内存错误 - 相反,您需要一个循环一次读取和写入一些大但有界的 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标准库至少和学习语言本身一样重要!-)

关于python - 处理文件的正确方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28001149/

相关文章:

python - 在 ipython 中编辑先前定义的类的好方法

python - 如何解密 django 哈希 sha256 密码?

python - 使用Elastichsearch Python客户端时出现ConnectionError

python - 导入错误 : No module named pytz after using easy_install

python - 已安装六个 1.4.1,但在 mac OS sierra 中 set( ['OpenSSL' ]) 需要六个 >=1.5.2

python - 使用 numpy.loadtxt 加载包含 float 和字符串的文本文件

python - 检查 for 循环变量是否驻留在列表的两个索引处

python - 模拟相关的多变量数据

python - 为什么 os.walk() 没有定义目录或文件?

python:用条件替换列表中的元素