У меня есть большой файл (500 МБ-1 ГБ), хранящийся в папке HTTP (S)
(скажем, https://example.com/largefile.zip
).
У меня есть доступ на чтение / запись к FTP-серверу
У меня есть обычные права пользователя (без sudo).
В рамках этих ограничений я хочу прочитать файл с HTTP-адреса HTTP через запросы и отправить его на FTP-сервер без предварительной записи на диск.
Так что обычно я делаю.
response=requests.get('https://example.com/largefile.zip', stream=True)
with open("largefile_local.zip", "wb") as handle:
for data in response.iter_content(chunk_size=4096):
handle.write(data)
и затем загружаю локальный файл на FTP.Но я хочу избежать дискового ввода-вывода.Я не могу смонтировать FTP как файловую систему fuse, потому что у меня нет прав суперпользователя.
В идеале я хотел бы сделать что-то вроде ftp_file.write()
вместо handle.write()
.Это возможно?В документации ftplib предполагается, что будут загружены только локальные файлы, а не response.content
.Так что в идеале я хотел бы сделать
response=requests.get('https://example.com/largefile.zip', stream=True)
for data in response.iter_content(chunk_size=4096):
ftp_send_chunk(data)
Я не уверен, как написать ftp_send_chunk()
.
Здесь есть похожий вопрос ( Python - Загрузить в памятифайл (сгенерированный вызовами API) в FTP чанками ).Мой вариант использования требует извлечения фрагмента из HTTP-URL и записи его на FTP.
PS: Решение, предоставленное в ответе (обертка вокруг urllib.urlopen), также будет работать с загрузками Dropbox.У меня были проблемы с работой с моим провайдером ftp, поэтому, наконец, я использовал dropbox, который работает надежно.
Обратите внимание, что Dropbox имеет функцию «добавить веб-загрузку» в API, которая делает то же самое (удаленная загрузка).Это работает только с "прямыми" ссылками.В моем случае использование http_url происходило от службы потоковой передачи, которая была ограничена IP.Таким образом, этот обходной путь стал необходимым.Вот код
import dropbox;
d = dropbox.Dropbox(<ACTION-TOKEN>);
f=FileWithProgress(filehandle);
filesize=filehandle.length;
targetfile='/'+fname;
CHUNK_SIZE=4*1024*1024
upload_session_start_result = d.files_upload_session_start(f.read(CHUNK_SIZE));
num_chunks=1
cursor = dropbox.files.UploadSessionCursor(session_id=upload_session_start_result.session_id,
offset=CHUNK_SIZE*num_chunks)
commit = dropbox.files.CommitInfo(path=targetfile)
while CHUNK_SIZE*num_chunks < filesize:
if ((filesize - (CHUNK_SIZE*num_chunks)) <= CHUNK_SIZE):
print d.files_upload_session_finish(f.read(CHUNK_SIZE),cursor,commit)
else:
d.files_upload_session_append(f.read(CHUNK_SIZE),cursor.session_id,cursor.offset)
num_chunks+=1
cursor.offset = CHUNK_SIZE*num_chunks
link = d.sharing_create_shared_link(targetfile)
url = link.url
dl_url = re.sub(r"\?dl\=0", "?dl=1", url)
dl_url = dl_url.strip()
print 'dropbox_url: ',dl_url;
Я думаю, что это даже можно сделать с помощью google-drive через их python api, но использование учетных данных с их оболочкой python слишком сложно для меня.Проверьте это 1 и это 2