用Paramiko上传一个类似文件的对象?

2024-05-07 05:06:44 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一堆代码如下:

with tempfile.NamedTemporaryFile() as tmpfile:
    tmpfile.write(fileobj.read()) # fileobj is some file-like object
    tmpfile.flush()
    try:
        self.sftp.put(tmpfile.name, path)
    except IOError:
        # error handling removed for ease of reading
        pass

有没有可能这样上传,而不必把文件写出来?


Tags: 代码readobjectisaswithsometempfile
2条回答

你在找什么?(doc page

SFTPClientget()put()函数采用路径而不是文件句柄,这使事情有点尴尬。

您可以为paramiko.SFTPClient编写一个包装器,以提供所需的功能。

以下是我未经测试的最佳尝试:

from paramiko import SFTPClient

class SFTPClient2(SFTPClient):
    def put(self, local_file, remotepath, callback=None, confirm=True):
        fl = source_file
        file_size = os.fstat(fl.fileno()).st_size
        try:
            fr = self.file(remotepath, 'wb')
            fr.set_pipelined(True)
            size = 0
            try:
                while True:
                    data = fl.read(32768)
                    if len(data) == 0:
                        break
                    fr.write(data)
                    size += len(data)
                    if callback is not None:
                        callback(size, file_size)
            finally:
                fr.close()
        finally:
            fl.close()
        if confirm:
            s = self.stat(remotepath)
            if s.st_size != size:
                raise IOError('size mismatch in put!  %d != %d' % (s.st_size, size))
        else:
            s = SFTPAttributes()
        return s

    def get(self, remotepath, local_file, callback=None):
        fr = self.file(remotepath, 'rb')
        file_size = self.stat(remotepath).st_size
        fr.prefetch()
        try:
            fl = local_file
            try:
                size = 0
                while True:
                    data = fr.read(32768)
                    if len(data) == 0:
                        break
                    fl.write(data)
                    size += len(data)
                    if callback is not None:
                        callback(size, file_size)
            finally:
                fl.close()
        finally:
            fr.close()
        s = os.fstat(fl.fileno())
        if s.st_size != size:
            raise IOError('size mismatch in get!  %d != %d' % (s.st_size, size))

如果可以工作,getput函数现在应该使用本地文件句柄而不是路径。

我所要做的就是从路径中删除打开文件的代码,并将获取文件大小的代码更改为使用os.fstat,而不是os.stat

更新从Paramiko1.10开始,您可以使用putfo

self.sftp.putfo(fileobj, path)

与使用paramiko.SFTPClient.put不同,您可以使用paramiko.SFTPClient.open,这将打开一个类似file的对象。你可以写信给他。像这样的:

f = self.sftp.open(path, 'wb')
f.write(fileobj.read())
f.close()

请注意,将paramiko数据分为32个KiB块可能是值得的,因为这是SSH协议所能处理的最大块,而无需将其分为多个包。

相关问题 更多 >