2

我一直在研究 SpiderOak 的这个Zipstream模块,它基本上允许您在不向光盘写入任何内容的情况下流式传输和压缩文件或文件夹。它产生大量不规则大小的数据。

现在,我正在尝试将目录上传到文件托管站点,该站点需要我在发布请求中发送fileapikey字段。有了请求,我必须为 apikey 构建一个字典,如下所示:

data = {'apikey': 'myapikey'}

并将整个 zipstream 读入字符串并将其传递给文件编码字典:

files = {'file': ('mydir.zip', the_string_that_is_a_zipped_dir)}

然后发出请求

r = requests.post(url, data=data, files=files).

这工作正常。但是,我想在将来传输更大的东西,并且从内存中读取整个文件是一个坏主意。我在请求高级部分中看到您可以发送生成器作为数据字段,但是我无法发送 api 密钥并且必须手动修改标头以设置内容类型和所有这些内容,因此它不起作用。还尝试从 api 密钥和 zip 文件生成器中形成字典,如下所示 data = { 'file': ('mydir.zip', generator()), 'apikey': 'myapikey' }

但这失败了(如预期的那样)。

有没有办法破解请求以使用生成器为多部分表单数据中的文件生成字符串?

4

1 回答 1

0

好的,经过一番努力,我设法在没有请求的情况下使它工作,而不是使用模块海报

首先,我在 zipstream 周围创建了一个文件对象包装器,如下所示:

from zipstream import ZipStream

class Zipit:
  def __init__( self, path):
    self.it = iter(ZipStream(path,compression=0))
    self.next_chunk = ""
    self.length = -1
    self.path = path
    self.__is_zipit__=''    
  @property
  def size(self):
    if self.length < 0:
      self.length = 0
      zip_object = ZipStream(self.path,compression=0)
      for data in zip_object:
        self.length += len(data)
    return self.length

  def growChunk( self ):
    self.next_chunk = self.next_chunk + self.it.next()
  def read( self, n ):
    if self.next_chunk == None:
      return None
    try:
      while len(self.next_chunk)<n:
        self.growChunk()
      rv = self.next_chunk[:n]
      self.next_chunk = self.next_chunk[n:]
      return rv
    except StopIteration:
      rv = self.next_chunk
      self.next_chunk = None
      return rv

为了有一个简单的api(代码无耻地改编自另一个关于SO的例子)。

然后按照海报的文档创建必要的多部分对象:

z = Zipit('/my/path/to/zip')

f = MultipartParam('file', fileobj=z, filesize=z.size, filename='test.zip',filetype='application/zip')
datagen, headers = multipart_encode([ f, ('akey', 'mykey')])

如果 fileobject 字段是Zipit实例,最后一个技巧是跳过重置:

   def reset(self):
        if hasattr(self.fileobj, '__is_zipit__'): return
        if self.fileobj is not None:
            self.fileobj.seek(0)
        elif self.value is None:
            raise ValueError("Don't know how to reset this parameter")

这对我有用。希望它对阅读本文的五位中的任何一个有所帮助。

于 2014-06-24T11:33:47.193 回答