从谷歌云存储流式传输gzip压缩文件

时间:2015-02-08 21:10:21

标签: python google-app-engine csv google-cloud-storage

我想直接从Google云端存储中读取压缩文件,然后使用Python csv包打开它们。 本地文件的代码是:

def reader(self):
    print "reading local compressed file: ", self._filename
    self._localfile = gzip.open(self._filename, 'rb')
    csvReader = csv.reader(self._localfile, delimiter=',', quotechar='"')
    return csvReader

我玩了几个GCS API(基于JSON,cloud.storage),但它们似乎都没有给我一些我可以通过gzip流式传输的东西。更重要的是,即使文件未压缩,我也无法打开文件并将其提供给cv.reader(Iterator类型)。

我的压缩CSV文件大约为500MB,而未压缩的文件最多使用几GB。我不认为这是一个好主意:1 - 在打开文件之前本地下载文件(除非我可以重叠下载和计算)或2 - 在计算之前将其完全打开内存。

最后,我当前在我的本地机器上运行此代码,但最终,我将转移到AppEngine,所以它也必须在那里工作。

谢谢!

2 个答案:

答案 0 :(得分:6)

使用GCScloudstorage.open(filename, 'r')将为您提供一个只读文件类对象(之前创建的类似于'w' :-),您可以使用它,一次一块,使用标准Python库zlib module,特别是zlib.decompressobj,当然,如果GS对象最初是以互补的方式创建的(使用zlib.compressobj)。

或者,为方便起见,您可以使用标准Python库gzip module,例如读取阶段,例如:

compressed_flo = cloudstorage.open('objname', 'r')
uncompressed_flo = gzip.GzipFile(fileobj=compressed_flo,mode='rb')
csvReader = csv.reader(uncompressed_flo)

,反之亦然,对于早期的写作阶段,当然。

请注意,当您在本地运行(使用dev_appserver)时,GCS客户端库使用本地磁盘文件来模拟GCS - 根据我的经验,这有利于开发目的,我可以使用{{ 1}}或其他工具,当我需要与我的本地工作站的“真实”GCS存储进行交互时... GCS适用于我需要来自我的GAE应用程序的此类交互(以及首先在本地开发所述GAE应用程序: - )。

答案 1 :(得分:4)

因此,您已经存储在GCS上的gzip压缩文件。您可以以类似流的方式处理存储在GCS 上的数据。也就是说,您可以同时下载,解压缩和处理。这避免了

  • 将解压缩的文件放在磁盘上
  • 必须等到下载完成才能处理数据。

gzip文件有一个小的页眉和页脚,正文是一个压缩流,由一系列块组成,每个块都可以自行解压缩。 Python的zlib package可以帮助你!

编辑:这是如何解压缩和分析zlib或gzip流的示例代码,纯粹基于zlib

import zlib
from collections import Counter


def stream(filename):
    with open(filename, "rb") as f:
        while True:
            chunk = f.read(1024)
            if not chunk:
                break
            yield chunk


def decompress(stream):
    # Generate decompression object. Auto-detect and ignore
    # gzip wrapper, if present.
    z = zlib.decompressobj(32+15)
    for chunk in stream:
        r = z.decompress(chunk)
        if r:
            yield r


c = Counter()
s = stream("data.gz")
for chunk in decompress(s):
    for byte in chunk:
        c[byte] += 1


print c

我使用GNU data.gz创建的示例文件gzip测试了此代码。

来自http://www.zlib.net/manual.html的引言:

  对于可选的gzip解码,

windowBits也可以大于15。加   32到windowBits用自动启用zlib和gzip解码   标头检测,或添加16只解码gzip格式(zlib   format将返回Z_DATA_ERROR)。如果正在解码gzip流,   strm-> adler是crc32而不是adler32。

  

gzip标头中包含的任何信息都不会保留[...]