从shutil文件复制线程获取进度 [英] Get progress back from shutil file copy thread

查看:142
本文介绍了从shutil文件复制线程获取进度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,可以将文件从src复制到dst:

I've got an application from which a file is copied from src to dst:

import shutil
from threading import Thread

t = Thread(target=shutil.copy, args=[ src, dst ]).start()

我希望让应用程序每5秒查询一次复制进度,而不会锁定应用程序本身.这可能吗?

I wish to have the application query the progress of the copy every 5 seconds without locking up the application itself. Is this possible?

我的目的是将此进度设置为QtGui.QLabel,以向用户提供有关文件副本的反馈.

My intention is to set this progress to a QtGui.QLabel to give the user feedback on the file copy.

使用线程shutil文件副本进行复制时可以实现吗?

Can this be achieved when copying using a threaded shutil file copy?

推荐答案

shutil.copy()不提供任何跟踪进度的选项,否.最多可以监视目标文件的大小(使用目标文件名上的os.*函数).

shutil.copy() doesn't offer any options to track the progress, no. At most you could monitor the size of the destination file (using os.* functions on the target filename).

替代方法是实现您自己的复制功能.实现确实非常简单; shutil.copy() 基本上是 shutil.copyfile() shutil.copymode() 调用; shutil.copyfile()依次将实际工作委托给 shutil.copyfileobj() * (链接到Python 3.8.2源代码).

The alternative would be to implement your own copy function. The implementation is really quite simple; shutil.copy() is basically a shutil.copyfile() plus shutil.copymode() call; shutil.copyfile() in turn delegates the real work to shutil.copyfileobj()* (links to the Python 3.8.2 source code).

实施自己的shutil.copyfileobj()以包括进度应该是微不足道的;注入对回调函数的支持,以便在每次复制另一个块时报告通知您的程序:

Implementing your own shutil.copyfileobj() to include progress should be trivial; inject support for a callback function to report inform your program each time another block has copied:

import os
import shutil

def copyfileobj(fsrc, fdst, callback, length=0):
    try:
        # check for optimisation opportunity
        if "b" in fsrc.mode and "b" in fdst.mode and fsrc.readinto:
            return _copyfileobj_readinto(fsrc, fdst, callback, length)
    except AttributeError:
        # one or both file objects do not support a .mode or .readinto attribute
        pass

    if not length:
        length = shutil.COPY_BUFSIZE

    fsrc_read = fsrc.read
    fdst_write = fdst.write

    copied = 0
    while True:
        buf = fsrc_read(length)
        if not buf:
            break
        fdst_write(buf)
        copied += len(buf)
        callback(copied)

# differs from shutil.COPY_BUFSIZE on platforms != Windows
READINTO_BUFSIZE = 1024 * 1024

def _copyfileobj_readinto(fsrc, fdst, callback, length=0):
    """readinto()/memoryview() based variant of copyfileobj().
    *fsrc* must support readinto() method and both files must be
    open in binary mode.
    """
    fsrc_readinto = fsrc.readinto
    fdst_write = fdst.write

    if not length:
        try:
            file_size = os.stat(fsrc.fileno()).st_size
        except OSError:
            file_size = READINTO_BUFSIZE
        length = min(file_size, READINTO_BUFSIZE)

    copied = 0
    with memoryview(bytearray(length)) as mv:
        while True:
            n = fsrc_readinto(mv)
            if not n:
                break
            elif n < length:
                with mv[:n] as smv:
                    fdst.write(smv)
            else:
                fdst_write(mv)
            copied += n
            callback(copied)

,然后在回调中将copied大小与文件大小进行比较.

and then, in the callback, compare the copied size with the file size.

请注意,在上述实现中,我们寻找机会为 binary 文件使用其他方法,您可以在其中使用原始_copyfileobj_readinto()实现比较.

Note that in the above implementation we look for the opportunity to use a different method for binary files, where you can use fileobj.readinto() and a memoryview object to avoid redundant data copying; see the original _copyfileobj_readinto() implementation for comparison.

* 脚注将实际工作委托给shutil.copyfileobj() :从Python 3.8 开始,在OS X和Linux上,copyfile()实现将文件复制委托给特定于操作系统的优化系统调用(

* footnote to … delegates the real work to shutil.copyfileobj(): As of Python 3.8, on OS X and Linux the copyfile() implementation delegates file copying to OS-specific, optimised system calls (to fcopyfile() and sendfile(), respectively) but these calls have no hooks whatsoever to track progress, and so if you need to track progress you'd want to disable these delegation paths anyway. On Windows the code uses the aforementioned _copyfileobj_readinto() function.

这篇关于从shutil文件复制线程获取进度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆