developer tip

Python 메모리 내 zip 라이브러리

optionbox 2020. 12. 27. 10:39
반응형

Python 메모리 내 zip 라이브러리


실제 디스크 파일을 사용하지 않고도 메모리에서 zip 아카이브를 조작 할 수있는 Python 라이브러리가 있습니까?

ZipFile 라이브러리를 사용하면 아카이브를 업데이트 할 수 없습니다. 유일한 방법은 디렉토리에 압축을 풀고 변경 한 다음 해당 디렉토리에서 새 zip을 만드는 것입니다. 디스크 액세스없이 zip 아카이브를 수정하고 싶습니다. 다운로드, 변경 및 다시 업로드 할 것이므로 저장할 이유가 없습니다.

Java의 ZipInputStream / ZipOutputStream과 유사한 것이 트릭을 수행 할 수 있지만 디스크 액세스를 피하는 인터페이스는 괜찮습니다.


Python 문서 에 따르면 :

class zipfile.ZipFile(file[, mode[, compression[, allowZip64]]])

  Open a ZIP file, where file can be either a path to a file (a string) or a file-like object. 

따라서 메모리에서 파일을 열려면 파일과 유사한 객체를 만듭니다 (아마도 BytesIO 사용 ).

file_like_object = io.BytesIO(my_zip_data)
zipfile_ob = zipfile.ZipFile(file_like_object)

Python의 In-Memory Zip 기사 에서 :

아래는 2008 년 5 월부터 Python으로 메모리 압축에 대한 내 게시물입니다. Posterous가 종료 된 이후 다시 게시되었습니다.

최근에 파이썬으로 메모리에 파일을 압축 할 수있는 유료 구성 요소가 있음을 알게되었습니다. 이것이 무료 여야한다는 점을 고려하여 다음 코드를 함께 던졌습니다. 아주 기본적인 테스트 만 거쳤으므로 오류가 발견되면 알려 주시면 업데이트하겠습니다.

import zipfile
import StringIO

class InMemoryZip(object):
    def __init__(self):
        # Create the in-memory file-like object
        self.in_memory_zip = StringIO.StringIO()

    def append(self, filename_in_zip, file_contents):
        '''Appends a file with name filename_in_zip and contents of 
        file_contents to the in-memory zip.'''
        # Get a handle to the in-memory zip in append mode
        zf = zipfile.ZipFile(self.in_memory_zip, "a", zipfile.ZIP_DEFLATED, False)

        # Write the file to the in-memory zip
        zf.writestr(filename_in_zip, file_contents)

        # Mark the files as having been created on Windows so that
        # Unix permissions are not inferred as 0000
        for zfile in zf.filelist:
            zfile.create_system = 0        

        return self

    def read(self):
        '''Returns a string with the contents of the in-memory zip.'''
        self.in_memory_zip.seek(0)
        return self.in_memory_zip.read()

    def writetofile(self, filename):
        '''Writes the in-memory zip to a file.'''
        f = file(filename, "w")
        f.write(self.read())
        f.close()

if __name__ == "__main__":
    # Run a test
    imz = InMemoryZip()
    imz.append("test.txt", "Another test").append("test2.txt", "Still another")
    imz.writetofile("test.zip")

Ethier가 제공 한 예제에는 몇 가지 문제가 있으며 그중 일부는 다음과 같습니다.

  • Windows의 실제 데이터에는 작동하지 않습니다. ZIP 파일은 바이너리이며 데이터는 항상 'wb'를 연 파일로 작성해야합니다.
  • ZIP 파일이 각 파일에 추가되므로 비효율적입니다. InMemoryZip속성 으로 열고 보관할 수 있습니다.
  • the documentation states that ZIP files should be closed explicitly, this is not done in the append function (it probably works (for the example) because zf goes out of scope and that closes the ZIP file)
  • the create_system flag is set for all the files in the zipfile every time a file is appended instead of just once per file.
  • on Python < 3 cStringIO is much more efficient than StringIO
  • doesn't work on Python 3 (the original article was from before the 3.0 release, but by the time the code was posted 3.1 had been out for a long time).

An updated version is available if you install ruamel.std.zipfile (of which I am the author). After

pip install ruamel.std.zipfile

or including the code for the class from here, you can do:

import ruamel.std.zipfile as zipfile

# Run a test
zipfile.InMemoryZipFile()
imz.append("test.txt", "Another test").append("test2.txt", "Still another")
imz.writetofile("test.zip")  

You can alternatively write the contents using imz.data to any place you need.

You can also use the with statement, and if you provide a filename, the contents of the ZIP will be written on leaving that context:

with zipfile.InMemoryZipFile('test.zip') as imz:
    imz.append("test.txt", "Another test").append("test2.txt", "Still another")

because of the delayed writing to disc, you can actually read from an old test.zip within that context.


PYTHON 3

import io
import zipfile

zip_buffer = io.BytesIO()
with zipfile.ZipFile(zip_buffer, "a", zipfile.ZIP_DEFLATED, False) as zip_file:
    for file_name, data in [('1.txt', io.BytesIO(b'111')), ('2.txt', io.BytesIO(b'222'))]:
        zip_file.writestr(file_name, data.getvalue())
with open('C:/1.zip', 'wb') as f:
    f.write(zip_buffer.getvalue())

ReferenceURL : https://stackoverflow.com/questions/2463770/python-in-memory-zip-library

반응형