53 votes

Ajout de dossiers à un fichier zip à l'aide de python

Je veux créer un fichier zip. Ajoutez un dossier au fichier zip, puis ajoutez un groupe de fichiers à ce dossier.

Je veux donc obtenir un fichier zip avec un seul dossier contenant des fichiers.

Je ne sais pas si c'est une mauvaise pratique d'avoir des dossiers dans des fichiers zip ou quelque chose comme ça mais google ne me donne rien sur le sujet.

J'ai commencé avec ça :

def addFolderToZip(myZipFile,folder):
    folder = folder.encode('ascii') #convert path to ascii for ZipFile Method
    for file in glob.glob(folder+"/*"):
            if os.path.isfile(file):
                print file
                myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED)
            elif os.path.isdir(file):
                addFolderToZip(myZipFile,file)

def createZipFile(filename,files,folders):
    curTime=strftime("__%Y_%m_%d", time.localtime())
    filename=filename+curTime;
    print filename
    zipFilename=utils.getFileName("files", filename+".zip")
    myZipFile = zipfile.ZipFile( zipFilename, "w" ) # Open the zip file for writing 
    for file in files:
        file = file.encode('ascii') #convert path to ascii for ZipFile Method
        if os.path.isfile(file):
            (filepath, filename) = os.path.split(file)
            myZipFile.write( file, filename, zipfile.ZIP_DEFLATED )

    for folder in  folders:   
        addFolderToZip(myZipFile,folder)  
    myZipFile.close()
    return (1,zipFilename)

(success,filename)=createZipFile(planName,files,folders);

Tiré de : http://mail.python.org/pipermail/python-list/2006-August/396166.html

Ce qui permet de se débarrasser de tous les dossiers et de placer tous les fichiers du dossier cible (et de ses sous-dossiers) dans un seul fichier zip. Je n'ai pas réussi à ajouter un dossier entier.

Si j'introduis le chemin d'accès à un dossier dans myZipFile.write, j'obtiens

IOError : [Errno 13] Permission refusée : '.. \packed\bin '

Toute aide est la bienvenue.

Question connexe : Comment zipper le contenu d'un dossier en utilisant python (version 2.5) ?

65voto

Gideon Points 404

Vous pouvez également utiliser shutil

import shutil

zip_name = 'path\to\zip_file'
directory_name = 'path\to\directory'

# Create 'path\to\zip_file.zip'
shutil.make_archive(zip_name, 'zip', directory_name)

Cela mettra le dossier entier dans le zip.

5 votes

Il est disponible uniquement sur Python 2.7+.

1 votes

Une chose intéressante à propos de cette méthode, elle ajoute .zip à votre desired_zipfile_name_no même s'il a déjà un .zip extension. Il renvoie ensuite le chemin complet vers lequel il a écrit avec la nouvelle extension. (Vous pouvez utiliser d'autres formats que zip, je suppose qu'il ajoute également leur extension).

1 votes

Il ne préserve pas les liens symboliques

52voto

RSabet Points 2887

Ok, après avoir compris ce que vous voulez, c'est aussi simple que d'utiliser le second argument de la fonction zipfile.write où vous pouvez utiliser ce que vous voulez :

import zipfile
myZipFile = zipfile.ZipFile("zip.zip", "w" )
myZipFile.write("test.py", "dir\\test.py", zipfile.ZIP_DEFLATED )

crée un fichier zip où test.py sera extrait dans un répertoire appelé dir

EDIT : J'ai dû une fois créer un répertoire vide dans un fichier zip : c'est possible. après le code ci-dessus, il suffit de supprimer le fichier test.py du fichier zip, le fichier disparaît, mais le répertoire vide reste.

0 votes

Oui, ça ressemble à la chose dont j'ai besoin. Après avoir lu le commentaire de 's, je comprends maintenant comment les "dossiers" dans les fichiers zip fonctionnent. Et j'ai trouvé du code dans la question connexe qui fait aussi ce que je veux, mais je n'ai pas compris comment. Je vais expérimenter un peu plus et revenir pour poster le code que j'ai réellement utilisé :)

0 votes

Et ce qui est mieux, c'est que c'est la même chose avec tarfile également, si jamais vous en créez un :) en tarfile le paramètre est appelé arcname pour le nom de l'archive.

4 votes

Pour que cela fonctionne sur toutes les plateformes, vous devez utiliser os.path.join("dir", "test.py").

16voto

tzot Points 32224

Un fichier zip n'a pas de structure de répertoire, il a juste un tas de chemins d'accès et de leur contenu. Ces chemins d'accès doit être relatif à un imaginaire dossier racine (le fichier ZIP lui-même). "../" préfixes ont pas de signification définie dans un fichier zip.

Considérez que vous avez un fichier, a et vous souhaitez le stocker dans un "dossier" à l'intérieur d'un fichier zip. Tout ce que vous avez à faire est de préfixer le nom de fichier avec un nom de dossier lors de l'enregistrement du fichier dans la zipfile:

zipi= zipfile.ZipInfo()
zipi.filename= "folder/a" # this is what you want
zipi.date_time= time.localtime(os.path.getmtime("a"))[:6]
zipi.compress_type= zipfile.ZIP_DEFLATED
filedata= open("a", "rb").read()

zipfile1.writestr(zipi, filedata) # zipfile1 is a zipfile.ZipFile instance

Je ne sais pas du tout ZIP implémentations permettant l'inclusion d'un vide dossier dans un fichier ZIP. Je pense à une solution de contournement (stockage d'un mannequin de nom de fichier dans le zip "dossier" qui doit être prise en compte à l'extraction), mais pas portable sur l'ensemble des implémentations.

2 votes

Je vois. Donc si j'ai bien compris, un fichier zip ne contient pas de dossiers. Mais si un fichier a un séparateur de chemin dans son nom, il est affiché comme un fichier dans un dossier dans la plupart des gestionnaires d'archives ? Et il sera créé de cette façon lorsque l'archive sera décompressée ?

1 votes

Correct. C'est difficile à faire, car les outils d'archivage échappent correctement les séparateurs de chemin dans les noms de fichiers. Votre programme python, cependant, peut forcer les noms non encodés.

0 votes

La façon correcte de créer l'entrée en python est writestr(directory, ''). Sous macOS, des entrées de zéro octet sont créées pour les répertoires

12voto

import zipfile
import os

class ZipUtilities:

    def toZip(self, file, filename):
        zip_file = zipfile.ZipFile(filename, 'w')
        if os.path.isfile(file):
                    zip_file.write(file)
            else:
                    self.addFolderToZip(zip_file, file)
        zip_file.close()

    def addFolderToZip(self, zip_file, folder): 
        for file in os.listdir(folder):
            full_path = os.path.join(folder, file)
            if os.path.isfile(full_path):
                print 'File added: ' + str(full_path)
                zip_file.write(full_path)
            elif os.path.isdir(full_path):
                print 'Entering folder: ' + str(full_path)
                self.addFolderToZip(zip_file, full_path)

def main():
    utilities = ZipUtilities()
    filename = 'TEMP.zip'
    directory = 'TEMP'
    utilities.toZip(directory, filename)

main()

Je suis en train de courir :

python tozip.py

Voici le journal :

havok@fireshield:~$ python tozip.py

File added: TEMP/NARF (7ª copia)
Entering folder: TEMP/TEMP2
File added: TEMP/TEMP2/NERF (otra copia)
File added: TEMP/TEMP2/NERF (copia)
File added: TEMP/TEMP2/NARF
File added: TEMP/TEMP2/NARF (copia)
File added: TEMP/TEMP2/NARF (otra copia)
Entering folder: TEMP/TEMP2/TEMP3
File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL
File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL (copia)
File added: TEMP/TEMP2/NERF
File added: TEMP/NARF (copia) (otra copia)
File added: TEMP/NARF (copia) (copia)
File added: TEMP/NARF (6ª copia)
File added: TEMP/NERF (copia) (otra copia)
File added: TEMP/NERF (4ª copia)
File added: TEMP/NERF (otra copia)
File added: TEMP/NERF (3ª copia)
File added: TEMP/NERF (6ª copia)
File added: TEMP/NERF (copia)
File added: TEMP/NERF (5ª copia)
File added: TEMP/NARF (8ª copia)
File added: TEMP/NARF (3ª copia)
File added: TEMP/NARF (5ª copia)
File added: TEMP/NERF (copia) (3ª copia)
File added: TEMP/NARF
File added: TEMP/NERF (copia) (copia)
File added: TEMP/NERF (8ª copia)
File added: TEMP/NERF (7ª copia)
File added: TEMP/NARF (copia)
File added: TEMP/NARF (otra copia)
File added: TEMP/NARF (4ª copia)
File added: TEMP/NERF
File added: TEMP/NARF (copia) (3ª copia)

Comme vous pouvez le voir, cela fonctionne, l'archive est également correcte. Il s'agit d'une fonction récursive qui peut zipper un dossier entier. Le seul problème est qu'elle ne crée pas de dossier vide.

A la vôtre.

4voto

Vous trouverez ci-dessous du code pour compresser un répertoire entier dans un fichier zip.

Cela semble fonctionner correctement pour créer des fichiers zip sous Windows et Linux. Les fichiers de sortie semblent s'extraire correctement sous Windows (fonction intégrée de dossiers compressés), WinZip, et 7-Zip) et linux. Cependant, les répertoires vides dans un fichier zip semblent être un problème épineux. La solution ci-dessous semble fonctionner mais la sortie de "zipinfo" sous linux est inquiétant. De plus, les permissions du répertoire ne sont pas définies correctement pour les répertoires vides dans l'archive zip. Cela semble nécessiter des recherches plus approfondies.

J'ai obtenu des informations de ce fil de discussion sur les critiques de la vélocité y ce fil de la liste de diffusion python .

Notez que cette fonction est conçue pour mettre les fichiers dans l'archive zip avec sans répertoire parent ou avec un seul répertoire parent. répertoires de tête dans les chemins du système de fichiers et ne les inclura pas dans l'archive de l'archive zip. C'est généralement le cas lorsque vous souhaitez simplement prendre un fichier de type répertoire et en faire un fichier zip qui peut être extrait à différents endroits. emplacements.

Les arguments des mots-clés :

dirPath -- chemin de chaîne vers le répertoire à archiver. C'est le seul élément argument requis. Il peut être absolu ou relatif, mais seulement un ou zéro répertoires principaux seront inclus dans l'archive zip.

zipFilePath -- chemin de chaîne vers le fichier zip de sortie. Il peut s'agir d'un chemin absolu ou relatif. Si le fichier zip existe déjà, il sera mis à jour. Si Sinon, il sera créé. Si vous voulez le remplacer à partir de zéro, supprimez-le. avant d'appeler cette fonction. (la valeur par défaut est calculée comme dirPath + ".zip")

includeDirInZip -- booléen indiquant si le répertoire de premier niveau devrait être inclus dans l'archive ou omis. (par défaut, True)

(Notez que StackOverflow semble ne pas réussir à imprimer mon python avec avec des chaînes entre guillemets, donc j'ai juste converti mes chaînes de doc en texte de post ici)

#!/usr/bin/python
import os
import zipfile

def zipdir(dirPath=None, zipFilePath=None, includeDirInZip=True):

    if not zipFilePath:
        zipFilePath = dirPath + ".zip"
    if not os.path.isdir(dirPath):
        raise OSError("dirPath argument must point to a directory. "
            "'%s' does not." % dirPath)
    parentDir, dirToZip = os.path.split(dirPath)
    #Little nested function to prepare the proper archive path
    def trimPath(path):
        archivePath = path.replace(parentDir, "", 1)
        if parentDir:
            archivePath = archivePath.replace(os.path.sep, "", 1)
        if not includeDirInZip:
            archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1)
        return os.path.normcase(archivePath)

    outFile = zipfile.ZipFile(zipFilePath, "w",
        compression=zipfile.ZIP_DEFLATED)
    for (archiveDirPath, dirNames, fileNames) in os.walk(dirPath):
        for fileName in fileNames:
            filePath = os.path.join(archiveDirPath, fileName)
            outFile.write(filePath, trimPath(filePath))
        #Make sure we get empty directories as well
        if not fileNames and not dirNames:
            zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/")
            #some web sites suggest doing
            #zipInfo.external_attr = 16
            #or
            #zipInfo.external_attr = 48
            #Here to allow for inserting an empty directory.  Still TBD/TODO.
            outFile.writestr(zipInfo, "")
    outFile.close()

Voici quelques exemples d'utilisation. Notez que si votre argument dirPath a plusieurs répertoires de tête, seul le DERNIER sera inclus par défaut. Passez includeDirInZip=False pour omettre tous les répertoires de tête.

zipdir("foo") #Just give it a dir and get a .zip file
zipdir("foo", "foo2.zip") #Get a .zip file with a specific file name
zipdir("foo", "foo3nodir.zip", False) #Omit the top level directory
zipdir("../test1/foo", "foo4nopardirs.zip")

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