Python将文件从HTTP(S)URL传输到FTP/Dropbox,无需磁盘写入(分块上传)

2024-06-01 05:29:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我在HTTP(S)位置存储了一个大文件(500 Mb-1Gb)
(说https://example.com/largefile.zip)。在

我对FTP服务器有读/写权限

我有正常的用户权限(没有sudo)。在

在这些限制条件下,我希望通过请求从httpurl读取文件并将其发送到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。但是我想避免磁盘I/O,因为我没有超级用户权限,所以我不能将FTP挂载为fuse文件系统。在

理想情况下,我会做类似ftp_file.write()而不是{}。有可能吗?ftplib文档似乎假定只上载本地文件,而不是response.content。所以理想情况下我想

^{pr2}$

我不知道怎么写ftp_send_chunk()。在

这里有一个类似的问题(Python - Upload a in-memory file (generated by API calls) in FTP by chunks)。我的用例需要从httpurl检索一个块并将其写入FTP。在

注:答案中提供的解决方案(包装urllib.urlopen)也可以用于dropbox上传。我在使用ftp提供商时遇到了问题,所以最终使用了dropbox,它工作可靠。在

请注意,Dropbox在api中有一个“addwebupload”功能,它可以做同样的事情(远程上传)。这只适用于“直接”链接。在我的用例中,http_url来自一个受i.p.限制的流媒体服务。因此,这种解决方法变得必要。 这是密码

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;

我认为甚至可以通过他们的pythonapi在googledrive上实现这一点,但是在python包装器中使用凭证对我来说太难了。检查这个1和这个2


Tags: 文件urlsizesessionftpfileszipcursor
1条回答
网友
1楼 · 发布于 2024-06-01 05:29:23

使用^{}应该很容易,因为它返回一个类似文件的对象,可以直接与^{}一起使用。在

ftp = FTP(host, user, passwd)

filehandle = urllib.request.urlopen(http_url)

ftp.storbinary("STOR /ftp/path/file.dat", filehandle)

如果要监视进度,请实现类似包装文件的对象,该对象将委托对filehandle对象的调用,但也将显示进度:

^{pr2}$

对于Python 2,请使用:

  • urllib.urlopen,而不是{}。在
  • filehandle.info().getheader('Content-Length')而不是{}

相关问题 更多 >