web-dev-qa-db-fra.com

Créer un .Zip en Python?

J'essaie de créer une fonction dans mon script qui zippe le contenu d'un répertoire source donné (src) dans un fichier Zip (dst). Par exemple, Zip('/path/to/dir', '/path/to/file.Zip'), où /path/to/dir est un répertoire et /path/to/file.Zip n'existe pas encore. Je ne pas veux compresser le répertoire lui-même, cela fait toute la différence dans mon cas. Je veux compresser les fichiers (et sous-répertoires) dans le répertoire. Voici ce que j'essaie:

def Zip(src, dst):
    zf = zipfile.ZipFile("%s.Zip" % (dst), "w")
    for dirname, subdirs, files in os.walk(src):
        zf.write(dirname)
        for filename in files:
            zf.write(os.path.join(dirname, filename))
    zf.close()

Cela crée un Zip qui est essentiellement /. Par exemple, si j'ai zippé /path/to/dir, extraire le Zip crée un répertoire contenant "chemin", avec "à" dans ce répertoire, etc.

Quelqu'un at-il une fonction qui ne cause pas ce problème?

Je ne saurais trop insister là-dessus, il a besoin pour compresser les fichiers dans le répertoire, pas le directoy lui-même.

34
tkbx

La méthode zipfile.write() prend un argument arcname facultatif qui spécifie le nom du fichier à l'intérieur du fichier zip.

Vous pouvez l'utiliser pour supprimer le chemin vers src au début. Ici, j'utilise os.path.abspath() pour m'assurer que src et le nom de fichier renvoyé par os.walk() ont un préfixe commun.

#!/usr/bin/env python2.7

import os
import zipfile

def Zip(src, dst):
    zf = zipfile.ZipFile("%s.Zip" % (dst), "w", zipfile.Zip_DEFLATED)
    abs_src = os.path.abspath(src)
    for dirname, subdirs, files in os.walk(src):
        for filename in files:
            absname = os.path.abspath(os.path.join(dirname, filename))
            arcname = absname[len(abs_src) + 1:]
            print 'zipping %s as %s' % (os.path.join(dirname, filename),
                                        arcname)
            zf.write(absname, arcname)
    zf.close()

Zip("src", "dst")

Avec une structure de répertoires comme celle-ci:

src
└── a
    ├── b
    │   └── bar
    └── foo

Le script imprime:

zipping src/a/foo as a/foo
zipping src/a/b/bar as a/b/bar

Et le contenu du fichier Zip résultant est:

Archive:  dst.Zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  01-28-13 11:36   a/foo
        0  01-28-13 11:36   a/b/bar
 --------                   -------
        0                   2 files
57
andrewdotn

D'après ce que je peux vous dire, vous êtes proche. Vous pouvez utiliser dirname et basename pour vous assurer que vous saisissez le bon nom de chemin:

>>> os.path.dirname("/path/to/dst")
'/path/to'
>>> os.path.basename("/path/to/dst")
'dst'

Ensuite, en utilisant chdir, vous pouvez vous assurer que vous êtes dans le parent afin que les chemins d'accès soient relatifs.

def Zip(src, dst):
    parent = os.path.dirname(dst)
    folder = os.path.basename(dst)

    os.chdir(parent):
    for dirname, subdirs, filenames in os.walk(folder):
        ...

Cela crée:

dst/a.txt
dst/b
dst/b/c.txt
...etc...

Si vous ne souhaitez pas inclure le nom "dst", vous pouvez simplement faire os.chdir(dst) puis os.walk('.').

J'espère que ça t'as aidé.

1
agoebel

Utilisez le paramètre arcname pour contrôler le nom/chemin dans le fichier Zip.

Par exemple, pour un fichier Zip qui ne contient que des fichiers, pas de répertoires:

zf.write(os.path.join(dirname, filename), arcname=filename)

Ou pour inventer un nouveau répertoire dans le fichier Zip:

zf.write(os.path.join(dirname, filename), arcname=os.path.join("my_Zip_dir", filename))
1
Jon-Eric