[英]Upload a file-like object with Paramiko?
I have a bunch of code that looks like this:我有一堆看起来像这样的代码:
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
Is it possible to do an upload like this without having to write the file out somewhere?是否可以进行这样的上传而不必将文件写在某处?
Update As of Paramiko 1.10 , you can use putfo :更新从Paramiko 1.10 开始,您可以使用putfo :
self.sftp.putfo(fileobj, path)
Instead of using paramiko.SFTPClient.put
, you can use paramiko.SFTPClient.open
, which opens a file
-like object.除了使用
paramiko.SFTPClient.put
,您还可以使用paramiko.SFTPClient.open
,它会打开一个类似file
的对象。 You can write to that.你可以写那个。 Something like this:
像这样的东西:
f = self.sftp.open(path, 'wb')
f.write(fileobj.read())
f.close()
Note that it may be worthwhile to feed paramiko data in 32 KiB chunks, since that's the largest chunk underlying SSH protocol can handle without breaking it into multiple packets.请注意,以 32 KiB 块提供 paramiko 数据可能是值得的,因为这是 SSH 协议底层可以处理的最大块,而无需将其分成多个数据包。
Is
StringIO
what you're looking for?
StringIO
是您要找的吗?
(
doc page )
(
文档页面)
SFTPClient
's get()
and put()
functions take paths and not file-handles, which makes things a bit awkward. SFTPClient
的get()
和put()
函数采用路径而不是文件句柄,这让事情有点尴尬。
You could write a wrapper for paramiko.SFTPClient
to give it the functionality that you want.您可以为
paramiko.SFTPClient
编写一个包装器来paramiko.SFTPClient
提供所需的功能。
Here's my best untested attempt:这是我最好的未经测试的尝试:
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))
If it works, the get
and put
functions should now take local file-handles rather than paths.如果它有效,
get
和put
函数现在应该采用本地文件句柄而不是路径。
All I had to do was get rid of the code that opens the file from the path, and change the code that gets the size of the file to use os.fstat
instead of os.stat
.我所要做的就是去掉从路径打开文件的代码,并将获取文件大小的代码更改为使用
os.fstat
而不是os.stat
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.