4

在 Python 中使用直接的方法复制文件通常是这样的:

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    while 1:
        buf = fsrc.read(length)
        if not buf:
            break
        fdst.write(buf)

(顺便说一下,这个代码片段来自 shutil.py)。

不幸的是,这在我的特殊用例中存在缺陷(涉及线程和非常大的缓冲区)[斜体部分稍后添加]。首先,这意味着每次调用 read() 都会分配一个新的内存块,当 buf 在下一次迭代中被覆盖时,该内存被释放,只是为了相同的目的再次分配新内存。这会减慢整个过程并给主机带来不必要的负载。

为了避免这种情况,我使用了 file.readinto() 方法,不幸的是,该方法被记录为已弃用且“不要使用”:

def copyfileobj(fsrc, fdst, length=16*1024):
    """copy data from file-like object fsrc to file-like object fdst"""
    buffer = array.array('c')
    buffer.fromstring('-' * length)
    while True:
        count = fsrc.readinto(buffer)
        if count == 0:
            break
        if count != len(buffer):
            fdst.write(buffer.toString()[:count])
        else:
            buf.tofile(fdst)

我的解决方案有效,但也有两个缺点:首先,不使用 readinto()。它可能会消失(文档说)。其次,使用 readinto() 我无法决定要读入缓冲区的字节数,而使用 buffer.tofile() 我无法决定要写入多少字节,因此最后一个块的特殊情况很麻烦(这也是不必要的昂贵的)。

我查看了 array.array.fromfile(),但它不能用于读取“所有存在”(读取,然后抛出 EOFError 并且不分发已处理项目的数量)。它也不是结束特例问题的解决方案。

有没有合适的方法来做我想做的事?也许我只是忽略了一个简单的缓冲区类或类似的东西,它可以满足我的需求。

4

2 回答 2

5

此代码片段来自 shutil.py

这是一个标准库模块。为什么不直接使用它?

首先,这意味着每次调用 read() 都会分配一个新的内存块,当 buf 在下一次迭代中被覆盖时,该内存被释放,只是为了相同的目的再次分配新内存。这会减慢整个过程并给主机带来不必要的负载。

与实际从磁盘中抓取一页数据所需的努力相比,这是微不足道的。

于 2012-03-20T17:25:12.613 回答
3

普通的 Python 代码不需要像这样的调整——但是,如果你真的需要所有的性能调整来从 Python 代码中读取文件(例如,你正在重写你编写的一些服务器 coe,并且已经为性能工作或内存使用)我宁愿直接使用 ctypes 调用操作系统 - 因此也可以根据需要执行低级别的副本。

甚至有可能简单地将“cp”可执行文件作为外部进程调用在您的情况下不是一个障碍(它会为您充分利用所有操作系统和文件系统级别的优化)。

于 2012-03-20T17:35:04.753 回答