Python:HTTP发布带有流媒体的大文件

时间:2010-03-23 18:31:58

标签: python http urllib2

我正在将可能较大的文件上传到网络服务器。目前我正在这样做:

import urllib2

f = open('somelargefile.zip','rb')
request = urllib2.Request(url,f.read())
request.add_header("Content-Type", "application/zip")
response = urllib2.urlopen(request)

但是,这会在发布之前将整个文件的内容读入内存。如何将文件流式传输到服务器?

6 个答案:

答案 0 :(得分:28)

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

答案 1 :(得分: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,请查看this旧帖子。

它提出了两个选择:

  1. Use mmap, Memory Mapped file object
  2. Patch httplib.HTTPConnection.send

答案 2 :(得分:3)

文档没有说你可以这样做,但是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的{​​{1}}类:

httplib.py

答案 3 :(得分:1)

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

答案 4 :(得分:1)

使用false库可以

requests

如上所述here in their docs

答案 5 :(得分:0)

无法(尚未)评论Brian的答案https://stackoverflow.com/a/30810626/9921853

urllib2.urlopen(URL,数据,标头)不会将标头作为参数,因此它将不起作用

下面是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()

请求模块很棒,但有时您无法安装任何额外的模块...