2012-06-11 4 views
0

У меня есть BytesIO, что я добавляю различные байты. Я хочу отправить это в urllib2.Request с помощью метода request.add_data. Как мне это сделать? Когда я попробуюPython - BytesIO и urllib2.add_data

# create request .... 
bytesio = BytesIO() 
bytesio.write(open("C:\img.jpg", "rb").read()) 
request.add_data(bytesio.getvalue()) 
bytesio.close() 

urllib2.urlopen(request) # error "expected buffer, got bytes" 

Что я делаю неправильно? Я новичок в Python и не знаю, как создать буфер из BytesIO. Кроме того, когда я просто попробую:

Я получаю операцию ввода-вывода в закрытом файле. Если я попытаюсь подождать, пока после того, как urlopen вызовет bytesio.close, запрос просто зависает, потому что он ждет закрытия байо.

Что мне нужно сделать?

Ответ

request.add_data(str(btyesio.getvalue())) 
bytesio.close() 

Кастинг в строку сделал его счастливым. Я не пытался увидеть, все ли работает с StringIO, и я не пробовал различия между Python 2.x и 3.x.

ответ

2

Самое простое решение: не используйте BytesIO, вам это не нужно.

urllib2.Request.add_data ожидает, что аргумент будет строкой, так что просто дайте ей один.

вызов:

bytesio.write(open("C:\img.jpg", "rb").read()) 

читает весь файл в память, а затем записывает его в bytesio сек памяти. Это означает, что у вас уже есть строка в mory, вам она не нужна дважды. Так что просто попробуйте:

request = urllib2.Request('http://www.site.com') 
with open("C:\img.jpg", "rb") as inputfile: 
    request.add_data(inputfile.read()) 
urllib2.urlopen(request) 
+0

Мне нужно добавить несколько элементов (файлы, обычный текст) ... Вот почему я использовал BytesIO для создания данных, прежде чем устанавливать его в запросе. – Chad

+0

Также: вы сказали, что ожидает строку. Строки и «буфер» одинаковы? – Chad

+0

строки в python имеют тот же интерфейс, что и ['buffer'] (http://docs.python.org/library/functions.html#buffer), поэтому все ожидания буфера также могут обрабатывать строку. В python2 вы, вероятно, должны использовать 'StringIO.StringIO' вместо' BytesIO'. В cPython 2.7 'bytes' совпадает с' str', может быть, IronPython здесь отличается. - и не забудьте установить заголовок «Content-Type», если вы не хотите, чтобы ваши данные отправлялись как «application/x-www-form-urlencoded» – mata

1

Просто удалите эту строку (добавьте его в конце):

bytesio.close() 

Другой код, кажется, работает для меня:

bytesio = BytesIO() 
bytesio.write(open("C:\img.jpg", "rb").read()) 
request = urllib2.Request('http://www.site.com') 
request.add_data(bytesio.getvalue()) 

urllib2.urlopen(request) # error "expected buffer, got bytes" 
bytesio.close() 

>>In [30]: urllib2.urlopen(request) 
Out[30]: <addinfourl at 52264040 whose fp = <socket._fileobject object at 0x315a450>> 

Или с помощью StringIO:

sio = StringIO.StringIO(open("C:\img.jpg", "rb").read()) 
request = urllib2.Request('http://www.site.com') 
request.add_data(sio.getvalue()) 

urllib2.urlopen(request) # error "expected buffer, got bytes" 
sio.close() 

>>In [14]: urllib2.urlopen(request) 
Out[14]: <addinfourl at 49067360 whose fp = <socket._fileobject object at 0x2dfb3d0>> 
+0

Извините, я все еще получаю сообщение об ожидаемом буфере, полученном байтах, когда я использую getvalue() и close() после urlopen(). Я использую IronPython 2.7, это вызовет любую проблему/разницу, если этот код работает на вас? – Chad

+0

Попробуйте StringIO.StringIO, я обновил этот пример. – Tisho

+0

Итак, StringIO и BytesIO тоже в Python 2.x, просто не в 3.x? – Chad

1

Не существует метода BytesIO.getvalue(), потому что он не нужен. Вместо этого просто держите ссылку на базовый буфер.

Это работает со списками и массивами, а также байты объектов, но это своего рода совпадение, а не фактического дизайна цели ...

+0

Можете ли вы показать пример того, как я «сохраняю ссылку на базовый буфер»? Я новичок в Python. Благодарю. – Chad

+0

Я думаю, вы можете проверить здесь http://docs.python.org/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference –

0

Вы можете получить всю информацию о виде BytesIO с:

esio.seek(0, os.SEEK_SET) 
esio.read() 

(SEEK_SET не нужен, но я использую его, чтобы разъяснить вещи)

Так что ваш пример:

# create request .... 
bytesio = BytesIO() 
bytesio.write(open("C:\img.jpg", "rb").read()) 
bytesio.seek(0, os.SEEK_SET) 
request.add_data(bytesio.read()) 
bytesio.close() 

urllib2.urlopen(request)