Это возможно, но вам нужно сделать несколько вещей:
- Подделать подсистему urllib2 для передачи дескриптора файла в httplib, добавив атрибут
__len__
, который возвращает len(data)
правильный размер, используемый для заполнения заголовка Content-Length. - Переопределите метод
read()
в дескрипторе файла: при вызове httplib read()
будет вызван ваш обратный вызов, что позволит вам вычислить процент и обновить вашиндикатор выполнения.
Это может работать с любым файловым объектом, но я обернул file
, чтобы показать, как он может работать с действительно большим файлом, передаваемым с диска:
import os, urllib2
from cStringIO import StringIO
class Progress(object):
def __init__(self):
self._seen = 0.0
def update(self, total, size, name):
self._seen += size
pct = (self._seen / total) * 100.0
print '%s progress: %.2f' % (name, pct)
class file_with_callback(file):
def __init__(self, path, mode, callback, *args):
file.__init__(self, path, mode)
self.seek(0, os.SEEK_END)
self._total = self.tell()
self.seek(0)
self._callback = callback
self._args = args
def __len__(self):
return self._total
def read(self, size):
data = file.read(self, size)
self._callback(self._total, len(data), *self._args)
return data
path = 'large_file.txt'
progress = Progress()
stream = file_with_callback(path, 'rb', progress.update, path)
req = urllib2.Request(url, stream)
res = urllib2.urlopen(req)
Вывод:
large_file.txt progress: 0.68
large_file.txt progress: 1.36
large_file.txt progress: 2.04
large_file.txt progress: 2.72
large_file.txt progress: 3.40
...
large_file.txt progress: 99.20
large_file.txt progress: 99.87
large_file.txt progress: 100.00