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

3voto

Dmitry Nedbaylo Points 168

Voici la fonction que j'utilise pour compresser un dossier :

import os
import os.path
import zipfile

def zip_dir(dirpath, zippath):
    fzip = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED)
    basedir = os.path.dirname(dirpath) + '/' 
    for root, dirs, files in os.walk(dirpath):
        if os.path.basename(root)[0] == '.':
            continue #skip hidden directories        
        dirname = root.replace(basedir, '')
        for f in files:
            if f[-1] == '~' or (f[0] == '.' and f != '.htaccess'):
                #skip backup files and all hidden files except .htaccess
                continue
            fzip.write(root + '/' + f, dirname + '/' + f)
    fzip.close()

3voto

z0r Points 470

Si vous regardez un fichier zip créé avec Info-ZIP, vous verrez que les répertoires sont effectivement répertoriés :

$ zip foo.zip -r foo
  adding: foo/ (stored 0%)
  adding: foo/foo.jpg (deflated 84%)
$ less foo.zip
  Archive:  foo.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 2013-08-18 14:32 00000000  foo/
  476320  Defl:N    77941  84% 2013-08-18 14:31 55a52268  foo/foo.jpg
--------          -------  ---                            -------
  476320            77941  84%                            2 files

Notez que l'entrée du répertoire a une longueur nulle et n'est pas compressée. Il semble que vous puissiez obtenir la même chose avec Python en écrivant le répertoire par son nom, mais en le forçant à ne pas utiliser la compression.

if os.path.isdir(name):
    zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_STORED)
else:
    zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_DEFLATED)

Cela peut valoir la peine de s'assurer arcname se termine par un / .

3voto

Razko Points 261

Le moyen le plus simple pour moi est d'utiliser zipfile CLI (interface en ligne de commande). Le CLI zipfile peut prendre des fichiers ou des dossiers comme arguments, et les ajouter récursivement à l'archive.

Donc si vous avez une hiérarchie de fichiers de :

- file1.txt
- folder1 
   - file2.txt
   - file3.txt

Si vous voulez que tout soit archivé dans le fichier "result.zip", il vous suffit d'écrire :

python -m zipfile -c result.zip file1.txt folder

Si vous souhaitez l'utiliser dans un code python et utiliser le module zipfile importé, vous pouvez appeler sa fonction principale de la manière suivante :

import zipfile
zipfile.main(['-c', 'result.zip', 'file1.md', 'folder'])

2voto

RSabet Points 2887

Après avoir ajouté quelques importations, votre code fonctionne bien pour moi, comment appelez-vous le script, peut-être pourriez-vous nous dire la structure du dossier de l' \packed\bin répertoire.

J'ai appelé votre code avec les arguments suivants :

planName='test.zip'
files=['z.py',]
folders=['c:\\temp']
(success,filename)=createZipFile(planName,files,folders)

`

0voto

Mizipzor Points 10952

Voici le code édité que j'ai exécuté. Il est basé sur le code ci-dessus, pris sur la liste de diffusion. J'ai ajouté les importations et créé une routine principale. J'ai également supprimé la manipulation du nom du fichier de sortie pour rendre le code plus court.

#!/usr/bin/env python

import os, zipfile, glob, sys

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):
    myZipFile = zipfile.ZipFile( filename, "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,filename)

if __name__=="__main__":
    #put everything in sys.argv[1] in out.zip, skip files
    print createZipFile("out.zip", [], sys.argv[1])

Au travail, sur ma machine Windows, ce code a bien fonctionné mais n'a pas créé de "dossiers" dans le fichier zip. Du moins, je me souviens qu'il l'a fait. Maintenant, à la maison, sur ma boîte Linux, le fichier zip créé semble être mauvais :

$ unzip -l out.zip 
Archive:  out.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of out.zip or
        out.zip.zip, and cannot find out.zip.ZIP, period.

Je ne sais pas si j'ai accidentellement cassé le code, je pense que c'est le même. Des problèmes de multi-plateforme ? Quoi qu'il en soit, cela n'a rien à voir avec ma question initiale : obtenir des dossiers dans le fichier zip. Je voulais juste poster le code que j'ai réellement exécuté, et non le code sur lequel j'ai basé mon code.

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