【问题标题】:How to use Paramiko getfo to download file from SFTP server to memory to process it如何使用 Paramiko getfo 将文件从 SFTP 服务器下载到内存进行处理
【发布时间】:2018-11-04 23:55:26
【问题描述】:

我正在尝试使用 Paramiko 从 SFTP 下载 CSV 文件(内存中)并将其导入 pandas 数据帧。

transport = paramiko.Transport((server, 22))
transport.connect(username=username, password=password)
sftp = paramiko.SFTPClient.from_transport(transport)

with open(file_name, 'wb') as fl:
    sftp.getfo(file_name, fl, callback=printTotals)
    df = pd.read_csv(fl, sep=' ')

下面的代码失败了,告诉我:

OSError: 文件未打开以供阅读

我假设我需要某种缓冲区或文件,例如 fl 的对象,因为 open 需要一个文件。我对这一切都比较陌生,所以如果有人可以提供帮助,我会很高兴。

【问题讨论】:

    标签: python pandas io sftp paramiko


    【解决方案1】:

    仍然允许您使用进度回调的简单解决方案是:

    • 使用BytesIO file-like object 将下载的文件存储到内存中;

    • 在下载文件后,你必须在开始阅读之前将文件指针返回到文件开头。

      with io.BytesIO() as fl:
          sftp.getfo(file_name, fl, callback=printTotals)
          fl.seek(0)
          df = pd.read_csv(fl, sep=' ')
      

    尽管使用此解决方案,您最终会将文件加载到内存中两次。


    更好的解决方案是实现一个自定义的类文件对象。它甚至可以让您同时下载和解析文件。

    class FileWithProgress:
    
        def __init__(self, fl):
            self.fl = fl
            self.size = fl.stat().st_size
            self.p = 0
    
        def read(self, blocksize):
            r = self.fl.read(blocksize)
            self.p += len(r)
            print(str(self.p) + " of " + str(self.size)) 
            return r
    

    并像这样使用它:

    with sftp.open(file_name, "rb") as fl:
        fl.prefetch()
        df = pd.read_csv(FileWithProgress(fl), sep=' ') 
    

    有关SFTPFile.prefetch 的电话,请参阅:
    Reading file opened with Python Paramiko SFTPClient.open method is slow


    如果你不需要进度监控,像这样的简单代码就可以了:

    with sftp.open(file_name, "rb") as fl:
        fl.prefetch()
        df = pd.read_csv(fl, sep=' ') 
    

    【讨论】:

    • 这正是我想要的!与此同时,我找到了另一种解决方案,它不如我无法通过回调来报告进度(请参阅下面的答案)。谢谢!
    【解决方案2】:

    我最终做的是一个简单的版本,不幸的是没有进度回调,我还需要rb 来阅读:

    with sftp.open(file_name, 'rb') as fl:
            df = pd.read_csv(fl, sep=' ')
    

    无论如何,马丁的答案正是我想要的!

    【讨论】:

      最近更新 更多