不使用临时文件生成zip流

问题描述 投票:7回答:3

我有一个python方法,需要从API收集lots数据,将其格式化为CSV,对其进行压缩并将结果流回。

我一直在使用Google搜索,找到的每个解决方案都需要写入临时文件或将整个档案保存在内存中。

内存绝对不是一种选择,因为我会很快获得OOM。写入临时文件有很多相关问题(此框目前仅使用磁盘存储日志,下载开始前的准备时间更长,文件清理问题等)。更何况它只是讨厌的事实。

我正在寻找一个可以让我做类似的事情的图书馆...

C = Compressor(outputstream)
C.BeginFile('Data.csv')
for D in Api.StreamResults():
    C.Write(D)
C.CloseFile()
C.Close()

换句话说,当我写入数据时,将会写入输出流的东西。

我已经设法在.Net和PHP中做到这一点-但我不知道如何在Python中实现它。

为了使事情更直观,通过“大量”数据,我的意思是我必须能够处理多达10 Gb的(原始明文)数据。这是大数据系统导出/转储过程的一部分。

python python-3.x stream compression zip
3个回答
7
投票

gzip module文档所述,您可以将类似文件的对象传递给GzipFile构造函数。由于python是鸭子类型的,因此您可以自由实现自己的流,如下所示:

import sys
from gzip import GzipFile

class MyStream(object):
    def write(self, data):
        #write to your stream...
        sys.stdout.write(data) #stdout, for example

gz= GzipFile( fileobj=MyStream(), mode='w'  )
gz.write("something")

6
投票

@@ goncaplopp的答案很好,但是如果在外部运行gzip,则可以实现更多的并行性。由于您正在收集大量数据,因此值得付出额外的努力。您将需要为Windows找到自己的压缩例程(有几种gzip实现,但是类似7z的方法也可以工作)。您还可以尝试像lz这样比gzip压缩更多的东西,具体取决于您在系统中需要优化的内容。

import subprocess as subp
import os

class GZipWriter(object):

    def __init__(self, filename):
        self.filename = filename
        self.fp = None

    def __enter__(self):
        self.fp = open(self.filename, 'wb')
        self.proc = subp.Popen(['gzip'], stdin=subp.PIPE, stdout=self.fp)
        return self

    def __exit__(self, type, value, traceback):
        self.close()
        if type:
            os.remove(self.filename)

    def close(self):
        if self.fp:
            self.fp.close()
            self.fp = None

    def write(self, data):
        self.proc.stdin.write(data)

with GZipWriter('sometempfile') as gz:
    for i in range(10):
        gz.write('a'*80+'\n')

0
投票

2020


您可以使用ZipFly


安装

pip install zipfly

所以,

from django.http import StreamingHttpResponse
import zipfly

paths = [
    {
        'filesystem': '/path/to/your/file1.mp4',
        'name': '/name/in/zip/file/file1.mp4', 
    },

    {
        'filesystem': '/path/to/your/file2.mp4',
        'name': '/name/in/zip/file/file2.mp4', 
    },        

]

# paths is a list of maps

zf = zipfly.ZipFly(paths=paths)
z = zf.generator()


response = StreamingHttpResponse(
   z, content_type='application/octet-stream'
)          

response['Transfer-Encoding'] = 'chunked'

return response 
© www.soinside.com 2019 - 2024. All rights reserved.