Библиотека zip в памяти Python

Есть ли библиотека Python, которая позволяет манипулировать zip-архивами в памяти без использования реальных файлов на диске?

Библиотека ZipFile не позволяет обновлять архив. Кажется, единственный способ - извлечь его в каталог, внести изменения и создать новый zip из этого каталога. Я хочу изменять zip-архивы без доступа к диску, потому что я буду загружать их, вносить изменения и загружать их снова, поэтому у меня нет причин их хранить.

Что-то похожее на ZipInputStream / ZipOutputStream в Java подойдет, хотя подойдет любой интерфейс, который вообще избегает доступа к диску.


person John B    schedule 17.03.2010    source источник
comment
В этом посте я ответил на тот же вопрос. stackoverflow.com/questions/60643857/   -  person Quinten Cabo    schedule 17.03.2020


Ответы (4)


Согласно документам 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)
person Jason R. Coombs    schedule 17.03.2010

ПИТОН 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())
person Vladimir    schedule 06.07.2017
comment
Ссылка на документацию. data может быть либо байтами, либо строками, и это отлично работало в Ubuntu и Python 3.6. - person Edgar H; 07.05.2019

Из статьи Архив в памяти в Python:

Ниже приведен мой пост от мая 2008 года о архивировании памяти с помощью Python, повторно опубликованный после того, как Posterous закрывается.

Недавно я заметил, что существует платный компонент для архивирования файлов в памяти с помощью Python. Учитывая, что это должно быть бесплатно, я собрал следующий код. Он прошел только базовое тестирование, поэтому, если кто-нибудь обнаружит какие-либо ошибки, дайте мне знать, и я обновлю его.

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")
person Justin Ethier    schedule 17.03.2010
comment
Полезная ссылка - это хороший пример того, как использовать объект ZipFile способом, описанным в ответе Джейсона. Спасибо - person John B; 17.03.2010
comment
Хорошо, рад, что вы нашли это полезным. - person Justin Ethier; 17.03.2010
comment
Обобщите содержание ссылки здесь, если она умирает, то и ваш ответ - person Ivo Flipse; 17.03.2013
comment
@IvoFlipse - Хорошее замечание. Я на всякий случай добавил весь этот контент в этот пост. - person Justin Ethier; 18.03.2013
comment
Не работает на самом деле под Windows или на Python 3.X, см. Мой ответ для обновления кода. - person Anthon; 01.11.2013
comment
Извините, что восстанавливаю старый пост, но я попробовал предложенное решение, но на выходе получил поврежденный zip-файл. Я использую python 2.7 в среде Windows, а в zip-файле есть только один файл. Имя файла внутри zip-архива может содержать до 40 символов. - person egesuato; 30.05.2018

В приведенном примере Этье есть несколько проблем, некоторые из которых являются серьезными:

  • не работает для реальных данных в Windows. ZIP-файл является двоичным, и его данные всегда должны быть записаны с открытым файлом 'wb'.
  • ZIP-файл добавляется к каждому файлу, это неэффективно. Его можно просто открыть и сохранить как атрибут InMemoryZip
  • в документации указано, что ZIP-файлы должны быть закрыты явно, это не делается в функции добавления (это, вероятно, работает (для примера), потому что zf выходит за рамки и закрывает ZIP-файл)
  • флаг create_system устанавливается для всех файлов в zip-файле каждый раз, когда файл добавляется, а не только один раз для каждого файла.
  • на Python ‹3 cStringIO намного эффективнее StringIO
  • не работает на Python 3 (исходная статья была опубликована до выпуска 3.0, но к тому времени, когда был опубликован код, версия 3.1 уже давно отсутствовала).

Обновленная версия доступна при установке ruamel.std.zipfile (автором которой является я). После

pip install ruamel.std.zipfile

или включая код для класса из здесь, вы можете:

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")  

Вы также можете записать содержимое с помощью imz.data в любое нужное вам место.

Вы также можете использовать оператор with, и если вы укажете имя файла, содержимое ZIP будет записано при выходе из этого контекста:

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

из-за отложенной записи на диск вы действительно можете читать из старого test.zip в этом контексте.

person Anthon    schedule 01.11.2013
comment
Почему бы не использовать io.BytesIO в Python 2? - person boxed; 14.10.2016
comment
@boxed Нет особой причины, кроме этого, вы должны проверить, использует ли BytesIO в 2.7 гораздо более быструю базовую реализацию C и не является ли уровень совместимости только Python, вызывающий StringIO (вместо CStringIO) - person Anthon; 17.10.2016
comment
Это действительно должно включать, по крайней мере, скелет любого кода, который вы создали, чтобы фактически ответить на вопрос, а не просто предлагать людям установить модуль. Если ничего другого, по крайней мере, ссылку на домашнюю страницу модуля. - person SilverbackNet; 20.12.2019
comment
Для случая python 2.7 я бы предложил преобразовать строки Unicode в строки utf8 перед переходом к функции Writestr (). Подробнее stackoverflow.com/a/67111639/565525. - person Robert Lujo; 15.04.2021