我有一堆看起来像这样的代码:
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
是否可以像这样进行上传而无需将文件写出来?
答案 0 :(得分:14)
更新自Paramiko 1.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()
请注意,以32 KiB块的形式提供paramiko数据可能是值得的,因为这是SSH协议可以处理的最大块,而不会将其分解为多个数据包。
答案 1 :(得分:2)
StringIO
您要找的是什么? (doc page)击>
SFTPClient
的{{1}}和get()
函数采用路径而不是文件句柄,这会让事情变得有点尴尬。
您可以为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))
和get
函数现在应该使用本地文件句柄而不是路径。
我所要做的就是摆脱从路径中打开文件的代码,并将获取文件大小的代码更改为使用put
而不是os.fstat
。