2013-06-07 12 views
5

Desidero inviare un file con python ftplib, da un sito ftp a un altro, in modo da evitare processi di lettura/scrittura.ftp invio di python bytesio stream

ho creare un flusso BytesIO:

myfile=BytesIO() 

E io con successo recuperare un file immagine dal sito ftp uno con retrbinary:

ftp_one.retrbinary('RETR P1090080.JPG', myfile.write) 

posso salvare questo oggetto di memoria a un file regolare:

fot=open('casab.jpg', 'wb') 

fot=myfile.readvalue() 

Ma non sono in grado di inviare questo flusso tramite ftp con storbinary. Ho pensato che questo avrebbe funzionato:

ftp_two.storbinary('STOR magnafoto.jpg', myfile.getvalue()) 

Ma non. ricevo un errore lungo msg che termina con 'buf = fp.read (blocksize) AttributeError: l'oggetto' str 'non ha attributo' read '

Ho provato anche molte combinazioni assurde, ma senza successo. Per inciso, sono anche abbastanza perplesso con quello che sto facendo davvero con myfoto.write. Non dovrebbe essere myfoto.write()?

Sono anche abbastanza indifferente a ciò che questo buffer fa o richiede. È quello che voglio troppo complicato da raggiungere? Dovrei semplicemente pingare i file con una scrittura/lettura intermedia nel mio sistema? Ty all

EDIT: grazie ad abanert ho capito bene. Per la cronaca, gli argomenti di storbinary erano errati e un myfile.seek (0) era necessario per 'riavvolgere' lo stream prima di inviarlo. Si tratta di un frammento di lavoro che si muove di un file tra due indirizzi FTP senza file fisico intermedio scrive:

import ftplib as ftp 
from io import BytesIO 

ftp_one=ftp.FTP(address1, user1, pass1) 
ftp_two=ftp.FTP(address2, user2, pass2) 
myfile=BytesIO() 
ftp_one.retrbinary ('RETR imageoldname.jpg', myfile.write) 
myfile.seek(0) 
ftp_two.storbinary('STOR imagenewname.jpg', myfile) 
ftp_one.close() 
ftp_two.close() 
myfile.close() 
+0

Nota a margine: "È possibile salvare questo oggetto di memoria in un file normale" in realtà non salva le informazioni. 'fot = open ('casab.jpg', 'wb')' crea un nuovo file vuoto, quindi 'fot = myfile.readvalue()' si dimentica dell'oggetto file, sostituendolo con una stringa. Hai bisogno di qualcosa come 'fot.write (myfile.readvalue())' per scrivere effettivamente in un file. (Puoi anche o non aver bisogno di 'myfile.seek (0)' per prima cosa.) – abarnert

risposta

3

Il problema è che si sta chiamando getvalue(). Basta non farlo:

ftp_two.storbinary('STOR magnafoto.jpg', myfile) 

storbinary richiede un oggetto simile a file che si può chiamare read on.

Fortunatamente, si dispone di un tale oggetto, myfile, a BytesIO. (Non è completamente chiaro dal tuo codice quale sia la sequenza di cose qui - se questo non funziona così, potresti aver bisogno di myfile.seek(0) o di crearlo in una modalità diversa o qualcosa del genere.Ma un BytesIO funzionerà con storbinary a meno che tu fare qualcosa di sbagliato.)

Ma invece di passare myfile, si passa myfile.getvalue(). E getvalue "Restituisce bytes contenente l'intero contenuto del buffer."

Così, invece di dare storbinary un oggetto simile a file che si può chiamare read su, si sta dando un oggetto bytes, che naturalmente è lo stesso di str in Python 2.x, e non è possibile chiama lo read su quello.


Per la vostra parte:

As an aside, I am also quite puzzled with what I am really doing with myfoto.write. Shouldnt it be myfoto.write() ?

Guarda the docs. Il secondo parametro non è un file, è una funzione di callback.

The callback function is called for each block of data received, with a single string argument giving the data block.

quello che vuoi è una funzione che aggiunge ogni blocco di dati al fine di myfoto. Mentre si potrebbe scrivere la propria funzione per farlo:

def callback(block_of_data): 
    myfoto.write(block_of_data) 

... dovrebbe essere abbastanza evidente che questa funzione fa esattamente la stessa cosa come il metodo myfoto.write. Quindi, puoi semplicemente passare quel metodo stesso.

Se non si capiscono i metodi associati, vedere Method Objects nel tutorial.


Questa flessibilità, come strano come sembra, permette di fare qualcosa di meglio che scaricare l'intero file in un buffer per inviare a un altro server. È possibile aprire le due connessioni contemporaneamente e utilizzare le richiamate per inviare ciascun buffer dal server di origine al server di destinazione non appena viene memorizzato, senza memorizzare mai più di un buffer.

Ma, a meno che non sia davvero necessario, probabilmente non si vuole passare attraverso tutta quella complessità.

Infatti, in generale, ftplib è un tipo di livello basso. E ha alcuni disegni (come il fatto che lo storbinary prende un file, mentre lo retrbinary prende un callback) che ha un senso totale a quel livello basso ma sembra molto strano da un livello più alto. Quindi, potresti voler guardare alcune delle librerie di livello superiore facendo un search at PyPI.

+0

L'ho fatto, ho passato myfile a storbinary. Crea un file, ma lungo 0 byte. – jose

+0

@jose: Beh, dovrai postare un esempio completo se lo vuoi debugare, ma la possibilità più probabile è quella che ho già menzionato nella risposta: Se crei un 'BytesIO 'vuoto in lettura-scrittura, scrivi in esso, poi leggere da esso, stai leggendo dalla fine, quindi non c'è niente da leggere. Puoi sistemarlo creando un nuovo 'BytesIO' leggibile dal buffer' BytesIO' scrivibile, o semplicemente chiamando 'seek (0)' su di esso. – abarnert

+0

sì, questo ha senso. Controllerò domani. È colpa mia se giocava con i file stream senza studiarli correttamente. Non avevo idea di questi flussi hanno una posizione di lettura. Ty per il tuo aiuto – jose