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

8
我正在使用Python 3.3.2和pysftp制作一个备份实用程序,将文件副本存储在我的网络上的另一台计算机上。
我已经知道如何使用pysftp传输这些文件,但是我想看到传输的进度(每秒字节数,完成百分比,剩余时间),而不是一些静态的打印语句表示传输已经开始或结束。
也许像这样(文件名:3.4MiB/s | 40%<#########=============> | 剩余0:03:54)
编辑: 如果我知道如何让pysftp的put命令产生信息,我可能可以构建一个进度条。我想知道的就是如何做到这一点。
编辑: 经过大量挖掘,我认为我在另一个问题中找到了答案: 如何使用paramiko查看(日志)文件传输进度?
6个回答

11

在获取和上传方法中都存在一个回调函数(参见官方文档)。

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

回调函数的格式可以如下:

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

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"

那么你可以在你的get或put命令中这样调用该函数:

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))

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

0
这是使用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

如果你知道终端,你可以很容易地编写自己的进度条。或者你可以使用progressbar。下面是文档中的一个简单示例:

@example
def example1():
    widgets = ['Test: ', Percentage(), ' ', Bar(marker=RotatingMarker()),
               ' ', ETA(), ' ', FileTransferSpeed()]
    pbar = ProgressBar(widgets=widgets, maxval=10000000).start()
    for i in range(1000000):
        # do something
        pbar.update(10*i+1)
    pbar.finish()

在这两种情况下,您都需要文件传输方法在传输期间产生一些内容。如果您可以让它产生接收到的字节,那么无论哪种方式,创建进度条都非常容易。

1
不回答用户的问题:我们如何在pysftp中实现这个? - Daniel van Flymen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接