如何通过pysftp监控文件传输进度

8 投票
6 回答
11176 浏览
提问于 2025-04-18 10:10

我正在使用 Python 3.3.2 和 pysftp 来制作一个备份工具,这个工具可以把文件的副本存储到我网络上另一台电脑上。

我已经知道怎么用 pysftp 来传输这些文件了,不过我想看到传输的进度,比如每秒传输多少字节、完成了多少百分比、还剩多少时间,而不是只看到一个静态的打印信息,告诉我传输开始或结束。

我想要的效果可能是这样的(文件名:3.4MiB/s | 40%<#########=============> | 还剩 0:03:54)

编辑:如果我知道怎么让 pysftp 的 put 命令提供这些信息,我可能就能做一个进度条,这正是我想知道的。

编辑:经过一番查找,我觉得我在另一个问题中找到了答案:

如何查看(记录)文件传输进度,使用 paramiko?

6 个回答

1

这就是使用 rich 库的效果。

import pysftp
from rich.progress import Progress

with pysftp.Connection(host=None, username=None, password=None) as sftp:
    file_to_download = '.'
    with Progress() as progress:
        task = progress.add_task(f"[red]Downloading {file_to_download} ...", total=None)

        sftp.get(
            file_to_download,
            local_path,
            callback=lambda so_far, total: progress.update(task, completed=so_far, total=total),
        )
3

如果你想使用tqdm这个进度条:

from tqdm import tqdm
import pysftp

class Progressbar(tqdm):
    def update_to(self, gathered: int, total: int):
        self.total = total
        self.update(gathered - self.n)

pb = Progressbar(
            desc=f"downloading {filename}",
            unit="ib",
            unit_divisor=1 << 20, #MiB
            unit_scale=True,
        )

with pysftp.Connection(host, username, password) as sftp:
    sftp.get(filename, callback=pb.update_to)

3

在编程中,有时候我们需要处理一些数据,比如从一个地方获取数据,然后在程序中使用这些数据。这个过程就像是从冰箱里拿食材,然后用这些食材做饭。

当我们说到“数据处理”,其实就是在说如何把这些食材(数据)整理好,准备好,才能做出美味的菜肴(程序的功能)。

有些时候,数据可能会有点乱,比如说冰箱里食材的种类太多,或者过期了,这时候我们就需要先把这些食材整理一下,挑选出新鲜的,才能开始做饭。

在编程中,我们也会遇到类似的情况,比如数据格式不对,或者缺少某些信息,这时候我们就需要用一些工具或者方法来清理和整理这些数据。

总之,数据处理就是让我们能更方便地使用数据,最终实现我们想要的功能,就像做饭一样,准备好食材才能做出好吃的菜。

import math, pysftp

with pysftp.Connection(host, username, password) as sftp:
    sftp.get(remotepath, localpath, callback=lambda x,y: progressbar(x,y))

def progressbar(x, y):
    ''' progressbar for the pysftp
    '''
    bar_len = 60
    filled_len = math.ceil(bar_len * x / float(y))
    percents = math.ceil(100.0 * x / float(y))
    bar = '=' * filled_len + '-' * (bar_len - filled_len)
    filesize = f'{math.ceil(y/1024):,} KB' if y > 1024 else f'{y} byte'
    sys.stdout.write(f'[{bar}] {percents}% {filesize}\r')
    sys.stdout.flush()

[============================================================] 100% 4,342 KB
9

你可以创建一个函数,每当进度达到(比如说)10%时就打印一次转移的状态:

progressDict={}
progressEveryPercent=10

for i in range(0,101):
    if i%progressEveryPercent==0:
        progressDict[str(i)]=""

def printProgressDecimal(x,y):
    if int(100*(int(x)/int(y))) % progressEveryPercent ==0 and progressDict[str(int(100*(int(x)/int(y))))]=="":
        print("{}% ({} Transfered(B)/ {} Total File Size(B))".format(str("%.2f" %(100*(int(x)/int(y)))),x,y))
        progressDict[str(int(100*(int(x)/int(y))))]="1"

然后你可以在你的获取或放置命令中这样调用这个函数:

sftp.get(eachFile,localpath=localDirectory+eachFile, callback=lambda x,y: printProgressDecimal(x,y))

一个示例输出是:

0.00% (32768 Transfered(B)/ 1108907068 Total File Size(B))
10.00% (110919680 Transfered(B)/ 1108907068 Total File Size(B))
20.00% (221806592 Transfered(B)/ 1108907068 Total File Size(B))
30.00% (332693504 Transfered(B)/ 1108907068 Total File Size(B))
40.00% (443580416 Transfered(B)/ 1108907068 Total File Size(B))
50.00% (554467328 Transfered(B)/ 1108907068 Total File Size(B))
60.00% (665354240 Transfered(B)/ 1108907068 Total File Size(B))
70.00% (776241152 Transfered(B)/ 1108907068 Total File Size(B))
80.00% (887128064 Transfered(B)/ 1108907068 Total File Size(B))
90.00% (998047744 Transfered(B)/ 1108907068 Total File Size(B))
100.00% (1108907068 Transfered(B)/ 1108907068 Total File Size(B))
11

在get和put方法中都有一个回调函数(可以查看官方的文档

get(remotepath, localpath=None, callback=None, preserve_mtime=False)

回调函数的样子可能是这样的:

lambda x,y: print("{} transfered out of {}".format(x,y))

撰写回答