Python:HTTP 使用流式传输发布大文件
- 2025-03-21 09:07:00
- admin 原创
- 38
问题描述:
我正在将可能很大的文件上传到 Web 服务器。目前我正在这样做:
import urllib2
f = open('somelargefile.zip','rb')
request = urllib2.Request(url,f.read())
request.add_header("Content-Type", "application/zip")
response = urllib2.urlopen(request)
但是,这会在发布之前将整个文件的内容读入内存。我怎样才能让它将文件流式传输到服务器?
解决方案 1:
通过阅读 systempuntoout 链接的邮件列表主题,我找到了解决方案的线索。
该mmap
模块允许您打开像字符串一样的文件。文件的部分内容会根据需要加载到内存中。
这是我现在使用的代码:
import urllib2
import mmap
# Open the file as a memory mapped string. Looks like a string, but
# actually accesses the file behind the scenes.
f = open('somelargefile.zip','rb')
mmapped_file_as_string = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
# Do the request
request = urllib2.Request(url, mmapped_file_as_string)
request.add_header("Content-Type", "application/zip")
response = urllib2.urlopen(request)
#close everything
mmapped_file_as_string.close()
f.close()
解决方案 2:
文档中没有说您可以这样做,但 urllib2 (和 httplib) 中的代码接受任何具有 read() 方法的对象作为数据。因此,使用打开的文件似乎可以解决问题。
您需要自行设置 Content-Length 标头。如果未设置,urllib2 将对数据调用 len(),而文件对象不支持此操作。
import os.path
import urllib2
data = open(filename, 'r')
headers = { 'Content-Length' : os.path.getsize(filename) }
response = urllib2.urlopen(url, data, headers)
这是处理您提供的数据的相关代码。它来自Python 2.7 中HTTPConnection
的类:httplib.py
def send(self, data):
"""Send `data' to the server."""
if self.sock is None:
if self.auto_open:
self.connect()
else:
raise NotConnected()
if self.debuglevel > 0:
print "send:", repr(data)
blocksize = 8192
if hasattr(data,'read') and not isinstance(data, array):
if self.debuglevel > 0: print "sendIng a read()able"
datablock = data.read(blocksize)
while datablock:
self.sock.sendall(datablock)
datablock = data.read(blocksize)
else:
self.sock.sendall(data)
解决方案 3:
您尝试过使用Mechanize吗?
from mechanize import Browser
br = Browser()
br.open(url)
br.form.add_file(open('largefile.zip'), 'application/zip', 'largefile.zip')
br.submit()
或者,如果您不想使用 multipart/form-data,请查看这篇旧帖子。
它提出了两种选择:
1. Use mmap, Memory Mapped file object
2. Patch httplib.HTTPConnection.send
解决方案 4:
尝试 pycurl。我没有设置任何可以接受不在multipart/form-data POST 中的大文件的内容,但这里有一个根据需要读取文件的简单示例。
import os
import pycurl
class FileReader:
def __init__(self, fp):
self.fp = fp
def read_callback(self, size):
return self.fp.read(size)
c = pycurl.Curl()
c.setopt(pycurl.URL, url)
c.setopt(pycurl.UPLOAD, 1)
c.setopt(pycurl.READFUNCTION, FileReader(open(filename, 'rb')).read_callback)
filesize = os.path.getsize(filename)
c.setopt(pycurl.INFILESIZE, filesize)
c.perform()
c.close()
解决方案 5:
使用requests
库你可以做
with open('massive-body', 'rb') as f:
requests.post('http://some.url/streamed', data=f)
正如他们的文档中提到的
解决方案 6:
以下是 Python 2 / Python 3 的工作示例:
try:
from urllib2 import urlopen, Request
except:
from urllib.request import urlopen, Request
headers = { 'Content-length': str(os.path.getsize(filepath)) }
with open(filepath, 'rb') as f:
req = Request(url, data=f, headers=headers)
result = urlopen(req).read().decode()
请求模块很棒,但有时您无法安装任何额外的模块......
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD