ftp отправляет поток байтов python

Я хочу отправить файл с ftplib python с одного ftp-сайта на другой, чтобы избежать процессов чтения/записи файлов.

Я создаю поток BytesIO:

myfile=BytesIO()

И я успешно извлек файл изображения с первого ftp-сайта с помощью retrbinary:

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

Я могу сохранить этот объект памяти в обычный файл:

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

fot=myfile.readvalue()

Но я не могу отправить этот поток через ftp с помощью storbinary. Я думал, что это сработает:

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

Но нет. я получаю длинное сообщение об ошибке, заканчивающееся на «buf = fp.read (размер блока) AttributeError: объект «str» не имеет атрибута «read»

Я также пробовал много абсурдных комбинаций, но безуспешно. Кроме того, я также весьма озадачен тем, что я действительно делаю с myfoto.write. Разве это не должно быть myfoto.write() ?

Я также совершенно не знаю, что делает или требует этот буфер. То, что я хочу, слишком сложно для достижения? Должен ли я просто пинговать файлы с промежуточной записью/чтением в моей системе? Ты все

РЕДАКТИРОВАТЬ: благодаря abanert я все понял. Для записи аргументы storbinary были неверными, и для «перемотки» потока перед его отправкой требовался myfile.seek(0). Это рабочий фрагмент, который перемещает файл между двумя ftp-адресами без записи в промежуточный физический файл:

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

person jose    schedule 07.06.2013    source источник
comment
Боковое примечание: я могу сохранить этот объект памяти в обычный файл, на самом деле вообще не сохраняет информацию. fot=open('casab.jpg', 'wb') создает новый пустой файл, затем fot=myfile.readvalue() забывает о файловом объекте, заменяя его строкой. Вам нужно что-то вроде fot.write(myfile.readvalue()) для записи в файл. (Вам также может понадобиться или не понадобиться сначала myfile.seek(0).)   -  person abarnert    schedule 08.06.2013
comment
Большое спасибо за подсказку, что потоки BytesIO нужно перематывать с помощью seek(0)! Это исправило мою проблему, когда загрузка работала, но файл был пуст \o/   -  person Fred    schedule 27.02.2021


Ответы (1)


Проблема в том, что вы звоните getvalue(). Только не делай этого:

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

storbinary требуется файлоподобный объект, который он может вызывать read вкл.

К счастью, у вас есть именно такой объект, myfile, BytesIO. . (Из вашего кода не совсем понятно, какова здесь последовательность действий — если это не работает как есть, вам может понадобиться myfile.seek(0) или создать его в другом режиме или что-то в этом роде. Но BytesIO будет работать с storbinary, если вы не сделать что-то не так)

Но вместо прохождения myfile вы проходите myfile.getvalue(). И getvalue "возвращает bytes, содержащий все содержимое файла буфер."

Таким образом, вместо того, чтобы предоставить storbinary файлоподобный объект, для которого он может вызывать read, вы даете ему объект bytes, который, конечно же, такой же, как str в Python 2.x, и вы не можете вызывать read для него. .


На ваше усмотрение:

Кроме того, я также весьма озадачен тем, что я действительно делаю с myfoto.write. Разве это не должно быть myfoto.write() ?

Просмотрите документацию. Второй параметр - это не файл, это функция обратного вызова.

Функция обратного вызова вызывается для каждого полученного блока данных с единственным строковым аргументом, задающим блок данных.

Вам нужна функция, которая добавляет каждый блок данных в конец myfoto. Хотя вы можете написать свою собственную функцию для этого:

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

… должно быть совершенно очевидно, что эта функция делает то же самое, что и метод myfoto.write. Таким образом, вы можете просто передать этот метод.

Если вы ничего не понимаете в связанных методах, см. раздел Объекты методов. в учебнике.


Эта гибкость, как ни странно, позволяет вам делать даже лучше, чем загружать весь файл в буфер для отправки на другой сервер. На самом деле вы можете открыть два соединения одновременно и использовать обратные вызовы для отправки каждого буфера с исходного сервера на целевой сервер по мере его получения, никогда не сохраняя ничего, кроме одного буфера.

Но, если вам это действительно не нужно, вы, вероятно, не хотите проходить через всю эту сложность.

Вообще-то ftplib какой-то низкоуровневый. И у него есть некоторые конструкции (например, тот факт, что storbinary принимает файл, а retrbinary принимает обратный вызов), которые имеют смысл на этом низком уровне, но кажутся очень странными на более высоком уровне. Таким образом, вы можете просмотреть некоторые библиотеки более высокого уровня, выполнив поиск в PyPI.

person abarnert    schedule 07.06.2013
comment
Я так и сделал, передал файл storbinary. Он создает файл, но длиной 0 байт. - person jose; 08.06.2013
comment
@jose: Ну, вам придется опубликовать полный пример, если вы хотите, чтобы он был отлажен, но наиболее вероятная возможность — это та, о которой я уже упоминал в ответе: если вы создаете пустой файл для чтения и записи BytesIO, затем записывайте в него, тогда читайте с него, вы читаете с конца, так что читать нечего. Вы можете исправить это, либо создав новый доступный для чтения BytesIO из буфера доступного для записи BytesIO, либо просто вызвав для него seek(0). - person abarnert; 08.06.2013
comment
да, это имеет смысл. Я проверю завтра. Моя вина в том, что я играю с файловыми потоками, не изучив их должным образом. Я понятия не имел, что эти потоки имеют позицию чтения. Ти за вашу помощь - person jose; 08.06.2013
comment
Играть с ними - отличный способ учиться. Может быть, попробовать поиграться с маленькими в интерактивном интерпретаторе, где вы можете напрямую видеть, что происходит на каждом шаге, вместо того, чтобы пытаться угадать, основываясь на эффектах более крупной программы, взаимодействующей с сервером. Но не отказывайтесь от обучения путем эксперимента в целом! - person abarnert; 08.06.2013
comment
Хорошо, попробовал, и простой myfile.seek(0) заработал. Спасибо, abanert, отредактирую основной пост, чтобы сохранить на будущее. Я играюсь с инструментами в режиме ожидания, но с двумя препятствиями (неверное прочтение аргументов в storbinary и игнорирование необходимости «перематывать» потоки данных) я совершенно потерялся. - person jose; 08.06.2013
comment
Спасибо за этот ответ, вы только что сэкономили мне кучу времени! - person Erty Seidohl; 13.08.2018