我有一个s3存储桶,其中没有大量的zip文件(以GB为单位)。我需要计算所有zip文件的数据长度。我经历了boto3,但没有得到。 我不确定它是否可以直接读取zip文件,但是我有一个过程-
注意:所有内容都不应下载到本地存储中。所有过程都从S3到S3。 任何建议表示赞赏。
答案 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压缩/解压缩。
您需要编写一个程序:
这可能最好在 Amazon EC2实例上完成,该实例对 Amazon S3 的访问时间较低。您可以使用AWS Lambda函数来完成此操作,但是它具有500MB磁盘存储限制和5分钟执行时间,这似乎不适用于您的情况。
如果您特别聪明,可以 可以下载每个zip文件的 part (“ ranged get”),并解释zipfile标头以获得以下内容的列表文件及其大小,从而避免了必须下载整个文件。