2010-03-23 30 views
13

Tôi đang tải lên các tệp lớn tiềm năng lên máy chủ web. Hiện tại tôi đang làm điều này:Python: HTTP Đăng tệp lớn có phát trực tuyến

import urllib2 

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

Tuy nhiên, điều này đọc toàn bộ nội dung của tệp vào bộ nhớ trước khi đăng. Làm thế nào tôi có thể có nó dòng tập tin vào máy chủ?

+0

liên quan: [file WSGI streaming với một máy phát điện] (http : //stackoverflow.com/questions/11811404/) –

+0

Related: http://stackoverflow.com/questions/2502596/python-http-post-a-large-file-with-streaming –

Trả lời

23

Đọc qua chuỗi danh sách gửi thư được liên kết bởi systempuntoout, tôi tìm thấy manh mối về giải pháp.

Mô-đun mmap cho phép bạn mở tệp hoạt động như một chuỗi. Các phần của tệp được tải vào bộ nhớ theo yêu cầu.

Dưới đây là đoạn code tôi đang sử dụng hiện nay:

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() 
+0

vui vì nó đã giúp :) – systempuntoout

+0

nó không hoạt động Am nhận được lỗi url – TinTin

+0

bạn có thể vui lòng xác nhận dòng dưới đây là chính xác: request = urllib2.Yêu cầu (url, mmapped_file_as_string) – TinTin

3

Bạn đã thử với Mechanize?

from mechanize import Browser 
br = Browser() 
br.open(url) 
br.form.add_file(open('largefile.zip'), 'application/zip', 'largefile.zip') 
br.submit() 

hoặc, nếu bạn không muốn sử dụng nhiều phần/biểu mẫu dữ liệu, hãy kiểm tra this bài đăng cũ.

Nó gợi ý hai lựa chọn:

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

Tôi không muốn gửi các tập tin enc oded "multipart/form-data". Điều này dường như làm điều đó. Tôi chỉ đang tìm kiếm một bài đăng thô. –

+0

Trên python 2.7 tùy chọn # 2 đã được thêm vá, kích thước khối là 8192, tôi tự hỏi tại sao .. hmmm. tiêu chuẩn/tiêu chuẩn về điều này là gì? – MistahX

1

Hãy thử pycurl. Tôi không có bất kỳ thiết lập nào sẽ chấp nhận tệp lớn mà không phải là trong POST/dữ liệu biểu mẫu đa dạng, nhưng đây là ví dụ đơn giản đọc tệp khi cần.

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() 
+1

Cảm ơn JimB. Tôi đã sử dụng điều này, ngoại trừ tôi có một vài người Windows sử dụng này, và tôi không muốn họ phải cài đặt bất cứ điều gì khác. –

3

Các tài liệu không nói rằng bạn có thể làm điều này, nhưng mã trong urllib2 (và httplib) chấp nhận bất kỳ đối tượng với một phương pháp read() như dữ liệu. Vì vậy, bằng cách sử dụng một tập tin mở dường như làm các trick.

Bạn sẽ cần tự đặt tiêu đề Độ dài nội dung. Nếu nó không được thiết lập, urllib2 sẽ gọi len() trên dữ liệu, các đối tượng tệp nào không hỗ trợ.

import os.path 
import urllib2 

data = open(filename, 'r') 
headers = { 'Content-Length' : os.path.getsize(filename) } 
response = urllib2.urlopen(url, data, headers) 

Đây là mã có liên quan xử lý dữ liệu bạn cung cấp. Đó là từ lớp HTTPConnection trong httplib.py bằng Python 2.7:

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) 
0

Sử dụng thư viện requests bạn có thể làm

with open('massive-body', 'rb') as f: 
    requests.post('http://some.url/streamed', data=f) 

như đã đề cập here in their docs

+0

Kích thước khối 8K vẫn được áp dụng, như httplib.py, send() L # 869 được gọi. –

Các vấn đề liên quan