2013-06-07 36 views
5

Chcę wysłać plik z python ftplib, z jednej strony ftp do drugiej, aby uniknąć plików do odczytu/zapisu.ftp wysyłając strumień bajtów bajtów

utworzyć strumień BytesIO:

myfile=BytesIO() 

A ja pomyślnie pobrać plik obrazu z ftp miejscu jednej z retrbinary:

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

mogę zapisywać obiekt pamięci do zwykłego pliku:

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

fot=myfile.readvalue() 

Ale nie mogę wysłać tego strumienia przez ftp ze storbinary. Myślałem, że to zadziała:

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

Ale nie robi. otrzymuję długi komunikat o błędzie kończący się na "buf = fp.read (blocksize) AttributeError: obiekt 'str' nie ma atrybutu 'odczyt'

Próbowałem także wielu absurdalnych kombinacji, ale bez powodzenia. Odkładając na bok, jestem również bardzo zaskoczony tym, co naprawdę robię z myfoto.write. Czy nie powinno to być myfoto.write()?

Jestem również całkiem nieświadoma tego, co robi ten bufor. Czy to, co chcę osiągnąć, jest zbyt skomplikowane? Czy powinienem po prostu pingować pliki z pośrednim zapisem/odczytem w moim systemie? Ty wszystkie

EDYCJA: dzięki abanert mam rzeczy prosto. Dla rekordu argumenty storbinary były błędne, a plik myfile.seek (0) był potrzebny do "przewinięcia" strumienia przed wysłaniem go. Jest to fragment pracy, która porusza plików między dwoma adresami ftp bez pośredniego zbioru fizycznego pisze:

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 boczna: "Mogę zapisać ten obiekt pamięci do zwykłego pliku" w rzeczywistości nie zapisuje w ogóle informacji. 'fot = open ('casab.jpg', 'wb')' tworzy nowy pusty plik, a następnie 'fot = myfile.readvalue()' zapomina o obiekcie pliku, zastępując go ciągiem znaków. Potrzebujesz czegoś takiego jak "fot.write (myfile.readvalue())", aby faktycznie zapisywać do pliku. (Możesz także, ale nie musi, najpierw "myfile.seek (0)"). – abarnert

Odpowiedz

3

Problemem jest to, że dzwonisz getvalue(). Tylko nie rób tego:

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

storbinary wymaga obiekt plikopodobny że może zadzwonić read dalej.

Na szczęście masz właśnie taki obiekt, myfile, a BytesIO. (Z twojego kodu nie wynika jasno, jak wygląda kolejność rzeczy - jeśli to nie działa tak, jak jest, możesz potrzebować myfile.seek(0) lub utworzyć je w innym trybie lub coś takiego, ale BytesIO będzie działać z storbinary, chyba że Zrób coś nie tak.)

Ale zamiast podania myfile, zdasz myfile.getvalue(). I getvalue "Zwraca bytes zawierający całą zawartość bufora."

Więc zamiast dawać storbinary obiektu plikopodobnym że można go nazwać read on, dajesz mu bytes Obiekt, który jest oczywiście taka sama jak w Pythonie 2.x str i nie można zadzwoń pod numer read.


Na swój bok:

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

Spójrz na the docs. Drugi parametr nie jest plikiem, to funkcja wywołania zwrotnego.

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

Co chcesz to funkcja, która dołącza każdy blok danych do końca myfoto. Choć można napisać własną funkcję, aby to zrobić:

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

... powinno być dość oczywiste, że ta funkcja działa dokładnie tak samo jak metody myfoto.write. Więc możesz po prostu przekazać tę samą metodę.

Jeśli nie rozumiesz metod związanych, zobacz Method Objects w samouczku.


Ta elastyczność, tak dziwaczna, jak się wydaje, pozwala zrobić coś jeszcze lepszego niż pobranie całego pliku do bufora, aby wysłać go na inny serwer. Możesz otworzyć oba połączenia w tym samym czasie i użyć wywołań zwrotnych, aby wysłać każdy bufor z serwera źródłowego do serwera docelowego po jego otrzymaniu, nie przechowując nigdy więcej niż jednego bufora.

Ale jeśli naprawdę tego nie potrzebujesz, prawdopodobnie nie chcesz przejść przez całą tę złożoność.

W rzeczywistości, ogólnie rzecz biorąc, ftplib jest niskiego poziomu. Ma też kilka projektów (np. Fakt, że storbinary pobiera plik, podczas gdy retrbinary przyjmuje wywołanie zwrotne), które na tym niskim poziomie mają ogólny sens, ale wydają się bardzo dziwne z wyższego poziomu. Tak więc możesz chcieć spojrzeć na niektóre biblioteki wyższego poziomu, robiąc search at PyPI.

+0

Zrobiłem to, przekazałem mój plik do wydania. Tworzy plik, ale ma 0 bajtów. – jose

+0

@jose: Cóż, będziesz musiał opublikować kompletny przykład, jeśli chcesz go debugować, ale najbardziej prawdopodobną możliwością jest ta, o której już wspomniałem w odpowiedzi: Jeśli utworzysz pusty odczyt-zapis 'BytesIO', to napisz do niego, a następnie czytać z niego, czytasz od końca, więc nie ma nic do czytania. Możesz to naprawić, tworząc nowe czytelne 'BytesIO' z zapisywalnego bufora' Bytesio' lub po prostu wywołując 'seek (0)' na nim. – abarnert

+0

tak, to ma sens. Sprawdzę jutro. Moja wina polega na zabawianiu strumieniami plików bez ich dokładnego studiowania. Nie miałem pojęcia, że ​​te strumienie mają pozycję do odczytu. Ty za pomoc – jose