使用boto3和python从Amazon s3读取zip文件

时间:2018-07-31 02:36:04

标签: python amazon-web-services amazon-s3 boto3

我有一个s3存储桶,其中没有大量的zip文件(以GB为单位)。我需要计算所有zip文件的数据长度。我经历了boto3,但没有得到。 我不确定它是否可以直接读取zip文件,但是我有一个过程-

  1. 与水桶连接。
  2. 从存储桶文件夹(假设文件夹为Mydata)中读取zip文件。
  3. 将zip文件提取到另一个名为Extracteddata的文件夹中。
  4. 读取Extracteddata文件夹并对文件进行操作。

注意:所有内容都不应下载到本地存储中。所有过程都从S3到S3。 任何建议表示赞赏。

2 个答案:

答案 0 :(得分:3)

您无法做的事,如John Rotenstein's answer所述。您必须下载zip文件-不一定要下载到本地存储,但至少要下载到本地内存,这会消耗您的本地带宽。无法在S3上运行任何代码。

但是,无论如何,也许有一种方法可以使您真正获得满意的生活。

如果您可以下载例如8KB的文件,而不是整个5GB的文件,这样就足够了吗?如果是这样,并且您愿意做一些工作,那么您很幸运。如果您必须下载例如1MB,但可以做得更少,该怎么办?


如果1MB听起来还不错,并且您愿意接受一些技巧:

您唯一想要的是计算zip文件中有多少个文件。对于zipfile,所有这些信息都可以在中央目录中找到,而在文件的末尾只有一小部分数据。

如果您拥有整个中央目录,即使您丢失了文件的其余部分,stdlib中的zipfile模块也可以很好地处理它。 尚无记录,但至少在最新的CPython和PyPy 3.x所包含的版本中,它肯定会记录。

所以,您可以做的是这样:

  • 发出HEAD请求以仅获取标头。 (在boto中,您可以通过head_object进行此操作。)
  • Content-Length标头中提取文件大小。
  • 发出带有Range标头的GET请求,使其仅从size-1048576下载到末尾。 (在boto中,我相信您可能必须调用get_object而不是download*便捷方法之一,并且必须自己格式化Range标头值。) / li>

现在,假设您在缓冲区buf中拥有了最后1MB:

z = zipfile.ZipFile(io.BytesIO(buf))
count = len(z.filelist)

通常,1MB绰绰有余。但是什么时候不是呢?好吧,这里的东西有些古怪。 zipfile模块知道您还需要多少字节,但是唯一可以提供信息的地方是异常描述的文本。所以:

try:
    z = zipfile.ZipFile(io.BytesIO(buf))
except ValueError as e:
    m = re.match(r'negative seek value -(\d+)', z.args[0])
    if not m:
        raise
    extra = int(m.group(1))
    # now go read from size-1048576-extra to size-1048576, prepend to buf, try again
count = len(z.filelist)

如果1MB的带宽听起来已经太多了,或者您不想依靠zipfile模块的未记录行为,那么您只需要做更多的工作即可。

在几乎每种情况下,您甚至都不需要整个中央目录,只需要total number of entries中的end of central directory record字段-中央目录末尾的一小块数据。

因此,请执行与上述相同的操作,但只读取最后8KB而不是最后1MB。

然后,基于zip format spec,编写自己的解析器。

当然,您不需要编写完整的解析器,甚至不需要编写一个完整的解析器。您只需要处理从total number of entries到末尾的字段即可。除了zip64 extensible data sector和/或.ZIP file comment以外,所有字段都是固定大小的字段。

有时(例如,对于带有大量注释的zip文件),您需要读取更多数据以获取计数。这应该很少见,但是如果由于某种原因在zip文件中更常见,则可以将8192个猜测值更改为更大的值。

答案 1 :(得分:0)

这不可能。

您可以将文件上传到Amazon S3,也可以下载文件。您可以查询对象列表并获取有关对象的元数据。但是, Amazon S3不提供计算,例如zip压缩/解压缩

您需要编写一个程序

  • 下载zip文件
  • 提取文件
  • 对文件执行操作

这可能最好在 Amazon EC2实例上完成,该实例对 Amazon S3 的访问时间较低。您可以使用AWS Lambda函数来完成此操作,但是它具有500MB磁盘存储限制和5分钟执行时间,这似乎不适用于您的情况。

如果您特别聪明,可以 可以下载每个zip文件的 part (“ ranged get”),并解释zipfile标头以获得以下内容的列表文件及其大小,从而避免了必须下载整个文件。