如何在Python中获取文件移动进度?

1 投票
3 回答
5712 浏览
提问于 2025-04-15 17:00

我有一个小脚本,用来整理我下载的文件,效果很好。不过,我想在移动大文件的时候,能看到进度,比如显示一个进度条或者百分比。目前我做的方式是:

print "moving..."
os.renames(pathTofile, newName)
print "done"

但我希望能看到类似进度条([..... ]这种样子)或者百分比直接打印到控制台上。

我不需要任何图形界面,只想要最简单、最省事的方法来显示操作进度。

谢谢!

3 个回答

0

这个例子的方法是在Benno的回答基础上进行扩展的,它通过估算剩余时间,并在复制完成后移除进度条。

def copy_large_file(src, dst):
    '''
    Copy a large file showing progress.
    '''
    print('copying "{}" --> "{}"'.format(src, dst))

    # Start the timer and get the size.
    start = time.time()
    size = os.stat(src).st_size
    print('{} bytes'.format(size))

    # Adjust the chunk size to the input size.
    divisor = 10000  # .1%
    chunk_size = size / divisor
    while chunk_size == 0 and divisor > 0:
        divisor /= 10
        chunk_size = size / divisor
    print('chunk size is {}'.format(chunk_size))

    # Copy.
    try:
        with open(src, 'rb') as ifp:
            with open(dst, 'wb') as ofp:
                copied = 0  # bytes
                chunk = ifp.read(chunk_size)
                while chunk:
                    # Write and calculate how much has been written so far.
                    ofp.write(chunk)
                    copied += len(chunk)
                    per = 100. * float(copied) / float(size)

                    # Calculate the estimated time remaining.
                    elapsed = time.time() - start  # elapsed so far
                    avg_time_per_byte = elapsed / float(copied)
                    remaining = size - copied
                    est = remaining * avg_time_per_byte
                    est1 = size * avg_time_per_byte
                    eststr = 'rem={:>.1f}s, tot={:>.1f}s'.format(est, est1)

                    # Write out the status.
                    sys.stdout.write('\r{:>6.1f}%  {}  {} --> {} '.format(per, eststr, src, dst))
                    sys.stdout.flush()

                    # Read in the next chunk.
                    chunk = ifp.read(chunk_size)

    except IOError as obj:
        print('\nERROR: {}'.format(obj))
        sys.exit(1)

    sys.stdout.write('\r\033[K')  # clear to EOL
    elapsed = time.time() - start
    print('copied "{}" --> "{}" in {:>.1f}s"'.format(src, dst, elapsed))

你可以在这里看到一个完整的可运行版本:https://gist.github.com/jlinoff/0f7b290dc4e1f58ad803

8

你不能通过 os.renames 来获取那种信息。最好的办法是自己写一个文件复制的操作,但在复制之前先用 stat 来查看文件的完整大小,这样你就能知道自己复制到哪儿了。

可以参考下面的代码:

source_size = os.stat(SOURCE_FILENAME).st_size
copied = 0
source = open(SOURCE_FILENAME, 'rb')
target = open(TARGET_FILENAME, 'wb')

while True:
    chunk = source.read(32768)
    if not chunk:
        break
    target.write(chunk)
    copied += len(chunk)
    print '\r%02d%%' % (copied * 100 / source_size),

source.close()
target.close()

不过要注意,这种方法可能会比使用 os.rename 慢很多。

1

其实没有办法显示进度条,因为“重命名”这个操作在系统中只是一条简单的命令。

需要注意的是,只有当你要移动的文件在不同的物理存储设备上时,这个“重命名”操作才会花时间。如果它们在同一个设备上,重命名几乎是瞬间完成的。如果你知道自己是在不同的存储设备之间复制数据,可能可以使用一些来自shutil模块的函数,比如copyfileobj。虽然没有现成的进度监控功能,但你可以自己实现一个类似文件的对象来跟踪进度。

撰写回答