Python:HTTP使用stream发布大文件
我将潜在的大file upload到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)
但是,这会在发布之前将整个文件的内容读入内存。 我怎样才能将文件stream式传输到服务器?
阅读systempuntoout链接的邮件列表线程,我发现了解决scheme的线索。
mmap
模块允许您打开像string一样的文件。 文件的一部分按需加载到内存中。
这里是我现在使用的代码:
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()
你尝试过机械化吗?
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,请检查这个旧post。
它提出了两个select:
1. Use mmap, Memory Mapped file object 2. Patch httplib.HTTPConnection.send
文档没有说你可以这样做,但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中的httplib.py
中的HTTPConnection
类:
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)
尝试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()
使用requests
库你可以做
with open('massive-body', 'rb') as f: requests.post('http://some.url/streamed', data=f)
正如他们的文档中提到的那样