我有一个s3存储桶,其中没有大量的压缩文件(以GB为单位)。我需要计算所有zip文件的数据长度。我通过boto3,但没有听懂。我不确定它是否可以直接读取zip文件,但是我有一个过程-
注意:所有内容都不应下载到本地存储中。所有过程都在S3到S3上进行。任何建议表示赞赏。
正如约翰·罗滕斯坦(John Rotenstein)的回答所解释的,您要做的是不可能的。您必须使用本地带宽将zipfile下载-不一定要下载到本地存储,但至少要下载到本地内存。无法在S3上运行任何代码。
但是,无论如何,也许有一种方法可以使您真正获得满意的结果。
例如,如果您可以下载价值8KB的文件,而不是整个5GB的文件,那就足够了吗?如果是这样,并且您愿意做一些工作,那么您很幸运。如果您必须下载例如1MB,但可以减少很多工作,该怎么办?
如果1MB听起来还不错,并且您愿意接受一些技巧:
您唯一想要的是计算zip文件中有多少个文件。对于zipfile,所有这些信息都可以在中央目录中找到,而在文件的末尾只有一小部分数据。
而且,如果您拥有整个中央目录,即使您丢失了文件的其余部分,zipfile
stdlib中的模块也可以很好地处理它。它不记录这样做,但是,至少在包括在最近的CPython的和PyPy 3.x中,肯定会在版本。
因此,您可以执行以下操作:
HEAD
发出仅获取标题的请求。(在中boto
,您可以使用进行此操作head_object
。)Content-Length
标题中提取文件大小。GET
发出带有Range
标头的请求,例如仅从头下载size-1048576
到最后。(在中boto
,我相信您可能必须调用get_object
而不是download*
便捷方法之一,并且必须自己格式化Range
标题值。)现在,假设您在缓冲区中有最后1MB的空间buf
:
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
在中央目录的最后数据的-an更小的块。
因此,执行与上述相同的操作,但只读取最后8KB而不是最后1MB。
然后,根据zip格式规范,编写自己的解析器。
当然,您不需要编写一个完整的解析器,甚至不需要编写一个完整的解析器。您只需要足够的内容来处理从头到尾的字段total number of entries
。除zip64 extensible data sector
和/或外,所有字段均为固定大小的字段.ZIP file comment
。
有时(例如,对于带有大量注释的zip文件),您将需要读取更多数据以获取计数。这应该很少见,但是如果由于某种原因在zip文件中更常见,则可以将8192猜测值更改为更大的值。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句