118 votes

Bibliothèque zip en mémoire Python

Existe-t-il une bibliothèque Python qui permette de manipuler des archives zip en mémoire, sans avoir à utiliser des fichiers disques ?

La bibliothèque ZipFile ne permet pas de mettre à jour l'archive. Le seul moyen semble être de l'extraire dans un répertoire, de faire vos modifications et de créer un nouveau zip à partir de ce répertoire. Je veux modifier des archives zip sans accès au disque, parce que je vais les télécharger, faire des changements, 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, mais n'importe quelle interface évitant l'accès au disque conviendrait.

119voto

Jason R. Coombs Points 11130

Selon la Documentation 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. 

Ainsi, pour ouvrir le fichier en mémoire, il suffit de créer un objet de type fichier (en utilisant éventuellement la fonction BytesIO ).

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

115voto

Vladimir Points 281

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

59voto

Justin Ethier Points 57486

Extrait de l'article Zip en mémoire en Python :

Vous trouverez ci-dessous un de mes articles datant de mai 2008 sur l'exploration de la mémoire avec Python, réaffiché depuis la fermeture de Posterous.

J'ai récemment remarqué qu'il existait un composant payant permettant de zipper des fichiers en mémoire avec Python. Considérant que c'est quelque chose qui devrait être gratuit, j'ai créé 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 mettrai à jour ce code.

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

22voto

Anthon Points 4119

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

  • ne fonctionne pas pour les données réelles sous Windows. Un fichier ZIP est binaire et ses données doivent toujours être écrites avec un fichier ouvert 'wb'
  • le fichier ZIP est complété pour chaque fichier, ce qui est inefficace. Il suffit de l'ouvrir et de le conserver en tant que fichier InMemoryZip attribut
  • la documentation indique que les fichiers ZIP doivent être fermés explicitement, ce qui n'est pas fait dans la fonction append (cela fonctionne probablement (pour l'exemple) parce que zf sort du champ d'application et que cela ferme le fichier ZIP)
  • l'indicateur create_system est activé pour tous les fichiers du fichier zip tous chaque fois qu'un fichier est ajouté au lieu d'une seule fois par fichier.
  • sur Python < 3 cStringIO est beaucoup plus efficace que StringIO
  • ne fonctionne pas avec Python 3 (l'article original date d'avant la sortie de la version 3.0, mais au moment où le code a été posté, la version 3.1 était sortie 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 à partir de aquí 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 à n'importe quel endroit.

Vous pouvez également utiliser la fonction 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")

grâce à l'écriture différée sur le disque, il est possible de lire un ancien disque. test.zip dans ce contexte.

6voto

Molossus Points 381

J'utilise Flask pour créer un fichier zip en mémoire et le renvoyer en téléchargement. Cet exemple s'inspire de celui de Vladimir. Les seek(0) a pris un certain temps à comprendre.

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

zip_buffer.seek(0)
return send_file(zip_buffer, attachment_filename='filename.zip', as_attachment=True)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X