web-dev-qa-db-fra.com

Python bibliothèque Zip en mémoire

Existe-t-il une bibliothèque Python qui permet la manipulation d'archives Zip en mémoire, sans avoir à utiliser de véritables fichiers disque?

La bibliothèque ZipFile ne vous permet pas de mettre à jour l'archive. La seule façon semble être de l'extraire dans un répertoire, d'apporter vos modifications et de créer un nouveau Zip à partir de ce répertoire. Je souhaite modifier les archives Zip sans accès au disque, car je vais les télécharger, apporter des modifications et les télécharger à nouveau, donc je n'ai aucune raison de les stocker.

Quelque chose de similaire à ZipInputStream/ZipOutputStream de Java ferait l'affaire, bien que n'importe quelle interface qui évite l'accès au disque convienne.

55
John B

Selon les documents 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. 

Donc, pour ouvrir le fichier en mémoire, créez simplement un objet de type fichier (peut-être en utilisant BytesIO ).

file_like_object = io.BytesIO(my_Zip_data)
zipfile_ob = zipfile.ZipFile(file_like_object)
73
Jason R. Coombs

De l'article Zip en mémoire en Python :

Ci-dessous est un de mes articles de mai 2008 sur la fermeture éclair en mémoire avec Python, republié depuis la fermeture de Posterous.

J'ai récemment remarqué qu'un composant payant est disponible pour les fichiers Zip en mémoire avec Python. Considérant que c'est quelque chose qui devrait être gratuit, j'ai rassemblé le code suivant. Il n'a subi que des tests très basiques, donc si quelqu'un trouve des erreurs, faites-le moi savoir et je le mettrai à jour.

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 __== "__main__":
    # Run a test
    imz = InMemoryZip()
    imz.append("test.txt", "Another test").append("test2.txt", "Still another")
    imz.writetofile("test.Zip")
42
Justin Ethier

L'exemple fourni par Ethier présente plusieurs problèmes, dont certains majeurs:

  • ne fonctionne pas pour les données réelles sur Windows. Un fichier Zip est binaire et ses données doivent toujours être écrites avec un fichier ouvert 'wb'
  • le fichier Zip est ajouté à chaque fichier, c'est inefficace. Il peut simplement être ouvert et conservé en tant qu'attribut InMemoryZip
  • la documentation indique que les fichiers Zip doivent être fermés de manière explicite, cela ne se fait pas dans la fonction append (cela fonctionne probablement (pour l'exemple) car zf sort de la portée et ferme le fichier Zip)
  • l'indicateur create_system est défini pour tous les fichiers du fichier zip à chaque fois qu'un fichier est ajouté au lieu d'une seule fois par fichier.
  • on Python <3 cStringIO est beaucoup plus efficace que StringIO
  • ne fonctionne pas sur Python 3 (l'article d'origine datait d'avant la version 3.0, mais au moment où le code a été publié, 3.1 était sorti depuis longtemps)).

Une version mise à jour est disponible si vous installez ruamel.std.zipfile (dont je suis l'auteur). Après

pip install ruamel.std.zipfile

ou en incluant le code de la classe de ici , vous pouvez faire:

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

Vous pouvez également écrire le contenu en utilisant imz.data à tout endroit dont vous avez besoin.

Vous pouvez également utiliser l'instruction with, et si vous fournissez un nom de fichier, le contenu du Zip sera écrit en quittant ce contexte:

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

en raison de l'écriture différée sur le disque, vous pouvez réellement lire à partir d'un ancien test.Zip dans ce contexte.

21
Anthon

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())
14
Vladimir