使用PyCurl从文件对象上传文件
我正在尝试上传一个文件,像这样:
import pycurl
c = pycurl.Curl()
values = [
("name", "tom"),
("image", (pycurl.FORM_FILE, "tom.png"))
]
c.setopt(c.URL, "http://upload.com/submit")
c.setopt(c.HTTPPOST, values)
c.perform()
c.close()
这样做是没问题的。不过,这种方法只适用于本地文件。如果我想要获取一个图片,像这样:
import urllib2
resp = urllib2.urlopen("http://upload.com/people/tom.png")
那我该如何把 resp.fp 作为一个文件对象传递,而不是先把它写入文件再传文件名呢?这样做可以吗?
1 个回答
4
在理想情况下,可能可以把两个数据流直接连接起来,但这样做并不是一个很稳妥的解决方案。这里面有很多麻烦的边界情况:
- 响应的连接可能还在接收数据,或者出现了卡顿,这样会导致你无法继续发送数据,进而中断POST请求(因为PycURL并不期待在当前“文件”的末尾之后还要等待数据)。
- 响应可能会重置,这样你就没有完整的文件了,但你已经发送了一部分数据——这种情况下该怎么办呢?
- 你用urllib获取的文件可能是分块编码的,所以你需要对MIME头进行一些操作才能重新组装——你不能只是盲目地转发数据。
- 你可能不知道你获取的文件有多大,因此很难在POST请求中提供正确的内容长度,这样你就得使用分块传输。
- 还有很多其他问题,我现在想不起来了……
你最好是先把文件暂时写到磁盘上,然后在确认你已经获取了完整文件后再进行POST请求。
如果你真的想这样做,最好的办法可能是实现一个自己的类,像文件一样管理这两个连接之间的桥梁(可以正确地缓冲、处理解码等)。
编辑:
根据你留下的评论——没错,你只需要设置 READFUNCTION
。可以查看这个文件上传的示例:
它正是通过在文件对象上做一个小的封装,并使用回调来读取数据,或者如果你不需要处理任何东西,可以直接把 READFUNCTION
的回调设置为 fp.read
。