2011-05-06 15 views
8

que tienen un montón de código que tiene este aspecto:¿Subir un objeto similar a un archivo con Paramiko?

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 

¿Es posible hacer un proceso de carga como este sin tener que escribir el archivo en algún lugar?

Respuesta

12

actualización A partir de paramiko 1.10, puede utilizar putfo:

self.sftp.putfo(fileobj, path) 

En lugar de utilizar paramiko.SFTPClient.put, puede utilizar paramiko.SFTPClient.open, lo que abre un objeto -como file. Puedes escribir a eso. Algo como esto:

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

Tenga en cuenta que puede ser útil para alimentar a los datos paramiko en 32 trozos KiB, ya que es el más grande protocolo SSH porción subyacente puede manejar sin romperlo en varios paquetes.

2

es StringIO ¿Qué está buscando? ( doc page)

SFTPClient 's get() y put() funciones toman caminos y Archivo no-mangos, que hace las cosas un poco incómodo.

Puede escribir un contenedor para paramiko.SFTPClient para darle la funcionalidad que desee.

Aquí es mi mejor intento no probado:

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

Si funciona, los get y put funciones que ahora debe tomar file-handles locales en lugar de caminos.

Todo lo que tenía que hacer era deshacerme del código que abre el archivo desde la ruta y cambiar el código que obtiene el tamaño del archivo para usar os.fstat en lugar de os.stat.

+0

No, ya tengo un objeto similar a un archivo, el problema es que 'paramiko.SFTPClient.put' utiliza una ruta en lugar de un archivo. En algunos casos, el "archivo" que estoy escribiendo en un archivo temporal ya es un objeto StringIO. –

+0

Eché un vistazo a la fuente de paramiko, y veo que las funciones solo toman caminos. Traté de escribir una pequeña envoltura para modificar esas funciones que he pegado arriba. – Acorn

Cuestiones relacionadas