13.5. "zipfile" — Travailler avec des archives ZIP
**************************************************

**Code source :** Lib/zipfile.py

======================================================================

Le format de fichier ZIP est une archive et un standard de compression
couramment utilisés. Ce module fournit des outils pour créer, écrire,
ajouter des données à et lister un fichier ZIP. L'utilisation avancée
de ce module requiert une certaine compréhension du format, comme
défini dans PKZIP Application Note.

Ce module ne gère pas pour l'instant les fichiers ZIP multi-disque. Il
gère les fichiers ZIP qui utilisent les extensions ZIP64 (c'est-à-dire
des fichiers d'une taille supérieure à 4 Go). Il gère le chiffrement
d'archives ZIP chiffrées, mais il ne peut pas pour l'instant créer de
fichier chiffré. Le déchiffrement est extrêmement lent car il est
implémenté uniquement en Python plutôt qu'en C.

Le module définit les éléments suivants :

exception zipfile.BadZipFile

   Erreur levée en cas de fichier ZIP non valide.

   Nouveau dans la version 3.2.

exception zipfile.BadZipfile

   Alias de "BadZipFile", pour la compatibilité avec les versions de
   Python précédentes.

   Obsolète depuis la version 3.2.

exception zipfile.LargeZipFile

   Erreur levée quand un fichier ZIP nécessite la fonctionnalité ZIP64
   mais qu'elle n'a pas été activée.

class zipfile.ZipFile

   Classe pour lire et écrire des fichiers ZIP. Voir la section Objets
   ZipFile pour les détails du constructeur.

class zipfile.PyZipFile

   Classe pour créer des archives ZIP contenant des bibliothèques
   Python.

class zipfile.ZipInfo(filename='NoName', date_time=(1980, 1, 1, 0, 0, 0))

   Classe utilisée pour représenter les informations d'un membre d'une
   archive. Les instances de cette classe sont retournées par les
   méthodes  "getinfo()" et "infolist()" des objets "ZipFile". La
   plupart des utilisateurs du module "zipfile" n'ont pas besoin de
   créer ces instances mais d'utiliser celles créées par ce module.
   *filename* doit être le nom complet du membre de l'archive et
   *date_time* doit être un *tuple*  contenant six champs qui décrit
   la date de dernière modification du fichier ; les champs sont
   décrits dans la section Objets ZipInfo.

zipfile.is_zipfile(filename)

   Retourne "True" si *filename* est un fichier ZIP valide basé sur
   son nombre magique, sinon retourne "False". *filename* peut aussi
   être un fichier ou un objet fichier-compatible.

   Modifié dans la version 3.1: Gestion des objets fichier et fichier-
   compatibles.

zipfile.ZIP_STORED

   Constante numérique pour un membre d'une archive décompressée.

zipfile.ZIP_DEFLATED

   Constante numérique pour la méthode habituelle de compression de
   ZIP. Nécessite le module "zlib".

zipfile.ZIP_BZIP2

   Constante numérique pour la méthode de compressions BZIP2.
   Nécessite le module "bz2".

   Nouveau dans la version 3.3.

zipfile.ZIP_LZMA

   Constante numérique pour la méthode de compressions LZMA. Nécessite
   le module "lzma".

   Nouveau dans la version 3.3.

   Note:

     La spécification du format de fichier ZIP inclut la gestion de la
     compression BZIP2 depuis 2001 et LZMA depuis 2006. Néanmoins,
     certains outils (comme certaines versions de Python) ne gèrent
     pas ces méthodes de compression et peuvent soit totalement
     refuser de traiter le fichier ZIP soit ne pas extraire certains
     fichiers.

Voir aussi:

  PKZIP Application Note
     Documentation sur le format de fichier ZIP par Phil Katz,
     créateur du format et des algorithmes utilisés.

  Info-ZIP Home Page
     Informations sur les programmes et les bibliothèques de
     développement d'archivage ZIP du projet Info-ZIP.


13.5.1. Objets ZipFile
======================

class zipfile.ZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True)

   Open a ZIP file, where *file* can be a path to a file (a string), a
   file-like object or a *path-like object*. The *mode* parameter
   should be "'r'" to read an existing file, "'w'" to truncate and
   write a new file, "'a'" to append to an existing file, or "'x'" to
   exclusively create and write a new file. If *mode* is "'x'" and
   *file* refers to an existing file, a "FileExistsError" will be
   raised. If *mode* is "'a'" and *file* refers to an existing ZIP
   file, then additional files are added to it.  If *file* does not
   refer to a ZIP file, then a new ZIP archive is appended to the
   file.  This is meant for adding a ZIP archive to another file (such
   as "python.exe").  If *mode* is "'a'" and the file does not exist
   at all, it is created. If *mode* is "'r'" or "'a'", the file should
   be seekable. *compression* is the ZIP compression method to use
   when writing the archive, and should be "ZIP_STORED",
   "ZIP_DEFLATED", "ZIP_BZIP2" or "ZIP_LZMA"; unrecognized values will
   cause "NotImplementedError" to be raised.  If "ZIP_DEFLATED",
   "ZIP_BZIP2" or "ZIP_LZMA" is specified but the corresponding module
   ("zlib", "bz2" or "lzma") is not available, "RuntimeError" is
   raised. The default is "ZIP_STORED".  If *allowZip64* is "True"
   (the default) zipfile will create ZIP files that use the ZIP64
   extensions when the zipfile is larger than 4 GiB. If it is  false
   "zipfile" will raise an exception when the ZIP file would require
   ZIP64 extensions.

   Si le fichier est créé avec le mode "'w'", "'x'" ou "'a'" et
   ensuite "fermé" sans ajouter de fichiers à l'archive, la structure
   appropriée pour un fichier archive ZIP vide sera écrite dans le
   fichier.

   ZipFile is also a context manager and therefore supports the "with"
   statement.  In the example, *myzip* is closed after the "with"
   statement's suite is finished---even if an exception occurs:

      with ZipFile('spam.zip', 'w') as myzip:
          myzip.write('eggs.txt')

   Nouveau dans la version 3.2: Ajout de la possibilité d'utiliser
   "ZipFile" comme un gestionnaire de contexte.

   Modifié dans la version 3.3: Ajout de la gestion de la compression
   "bzip2" et "lzma".

   Modifié dans la version 3.4: Les extensions ZIP64 sont activées par
   défaut.

   Modifié dans la version 3.5: Ajout de la gestion de l'écriture dans
   des flux non navigables. Ajout de la gestion du mode "x".

   Modifié dans la version 3.6: Auparavant, une simple exception
   "RuntimeError" était levée pour des valeurs de compression non
   reconnues.

   Modifié dans la version 3.6.2: Le paramètre *file* accepte un objet
   fichier-compatible *path-like object*.

ZipFile.close()

   Ferme l'archive. Vous devez appeler "close()" avant de terminer
   votre programme ou des informations essentielles n'y seront pas
   enregistrées.

ZipFile.getinfo(name)

   Retourne un objet "ZipInfo" avec les informations du membre *name*
   de l'archive. Appeler "getinfo()" pour un nom non contenu dans
   l'archive lève une exception "KeyError".

ZipFile.infolist()

   Retourne une liste contenant un objet "ZipInfo" pour chaque membre
   de l'archive. Les objets ont le même ordre que leurs entrées dans
   le fichier ZIP présent sur disque s'il s'agissait d'une archive
   préexistante.

ZipFile.namelist()

   Retourne une liste des membres de l'archive indexés par leur nom.

ZipFile.open(name, mode='r', pwd=None, *, force_zip64=False)

   Accède un membre de l'archive en tant qu'objet fichier-compatible
   binaire. *name* peut être soit le nom d'un fichier au sein de
   l'archive soit un objet "ZipInfo". Le paramètre *mode*, si inclus,
   doit être défini à "'r'" (valeur par défaut) ou "'w'".  *pwd* est
   le mot de passe utilisé pour déchiffrer des fichiers ZIP chiffrés.

   "open()" est aussi un gestionnaire de contexte et gère ainsi la
   déclaration "with" :

      with ZipFile('spam.zip') as myzip:
          with myzip.open('eggs.txt') as myfile:
              print(myfile.read())

   With *mode* "'r'" the file-like object ("ZipExtFile") is read-only
   and provides the following methods: "read()", "readline()",
   "readlines()", "__iter__()", "__next__()".  These objects can
   operate independently of the ZipFile.

   Avec "mode='w'" un descripteur de fichier en écriture est retourné,
   gérant la méthode "write()". Quand le descripteur d'un fichier
   inscriptible est ouvert, tenter de lire ou écrire d'autres fichiers
   dans le fichier ZIP lève une exception "ValueError".

   Lors de l'écriture d'un fichier, si la taille du fichier n'est pas
   connue mais peut être supérieure à 2 GiO, spécifiez
   "force_zip64=True" afin de vous assurer que le format d'en-tête est
   capable de supporter des fichiers volumineux. Si la taille du
   fichier est connue à l'avance, instanciez un objet "ZipInfo" avec
   l'attribut "file_size" défini et utilisez-le en tant que paramètre
   *name*.

   Note:

     Les méthodes "open()", "read()" et "extract()" peuvent prendre un
     nom de fichier ou un objet "ZipInfo". Cela est appréciable
     lorsqu'on essaie de lire un fichier ZIP qui contient des membres
     avec des noms en double.

   Modifié dans la version 3.6: Suppression de la gestion de
   "mode='U'".  Utilisez "io.TextIOWrapper" pour lire des fichiers
   texte compressés en mode *universal newlines*.

   Modifié dans la version 3.6: La méthode "open()" peut désormais
   être utilisée pour écrire des fichiers dans l'archive avec l'option
   "mode='w'".

   Modifié dans la version 3.6: Appeler "open()" sur un fichier
   ZipFile fermé lève une erreur "ValueError". Précédemment, une
   erreur "RuntimeError" était levée.

ZipFile.extract(member, path=None, pwd=None)

   Extrait un membre de l'archive dans le répertoire courant ;
   *member* doit être son nom complet ou un objet "ZipInfo". Ses
   propriétés de fichier sont extraites le plus fidèlement possible.
   *path* spécifie un répertoire différent où l'extraire. *member*
   peut être un nom de fichier ou un objet "ZipInfo". *pwd* est le mot
   de passe utilisé pour les fichiers chiffrés.

   Retourne le chemin normalisé créé (un dossier ou un nouveau
   fichier).

   Note:

     Si le nom de fichier d'un membre est un chemin absolu, le
     disque/partage UNC et les (anti)slashes de départ seront
     supprimés, par exemple *///foo/bar`* devient "foo/bar" sous Unix
     et "C:\foo\bar" devient "foo\bar" sous Windows. Et tous les
     composants "".."" dans le nom de fichier d'un membre seront
     supprimés, par exemple "../../foo../../ba..r" devient
     "foo../ba..r". Sous Windows les caractères illégaux (":", "<",
     ">", "|", """, "?" et "*") sont remplacés par un *underscore*
     ("_").

   Modifié dans la version 3.6: Appeler "extract()" sur un fichier
   ZipFile fermé lève une erreur "ValueError". Précédemment, une
   erreur "RuntimeError" était levée.

   Modifié dans la version 3.6.2: Le paramètre *path* accepte un objet
   chemin-compatible *path-like object*.

ZipFile.extractall(path=None, members=None, pwd=None)

   Extrait tous les membres de l'archive dans le répertoire courant.
   *path* spécifie un dossier de destination différent. *members* est
   optionnel et doit être un sous-ensemble de la liste retournée par
   "namelist()". *pwd* est le mot de passe utilisé pour les fichiers
   chiffrés.

   Avertissement:

     N'extrayez jamais d'archives depuis des sources non fiables sans
     inspection préalable. Il est possible que des fichiers soient
     créés en dehors de *path*, par exemple des membres qui ont des
     chemins de fichier absolus commençant par ""/"" ou des noms de
     fichier avec deux points "".."".  Ce module essaie de prévenir
     ceci. Voir la note de "extract()".

   Modifié dans la version 3.6: Appeler "extractall()" sur un fichier
   ZipFile fermé lève une erreur "ValueError". Précédemment, une
   erreur "RuntimeError" était levée.

   Modifié dans la version 3.6.2: Le paramètre *path* accepte un objet
   chemin-compatible *path-like object*.

ZipFile.printdir()

   Affiche la liste des contenus de l'archive sur "sys.stdout".

ZipFile.setpassword(pwd)

   Définit *pwd* comme mot de passe par défait pour extraire des
   fichiers chiffrés.

ZipFile.read(name, pwd=None)

   Retourne les octets du fichier *name* dans l'archive. *name* est le
   nom du fichier dans l'archive ou un objet "ZipInfo". L'archive doit
   être ouverte en mode lecture ou ajout de données. *pwd* est le mot
   de passe utilisé pour les fichiers chiffrés et, si spécifié, écrase
   le mot de passe par défaut défini avec "setpassword()". Appeler
   "read()" sur un fichier ZipFile qui utilise une méthode de
   compression différente de "ZIP_STORED", "ZIP_DEFLATED", "ZIP_BZIP2"
   ou "ZIP_LZMA" lève une erreur "NotImplementedError". Une erreur est
   également levée si le module de compression n'est pas disponible.

   Modifié dans la version 3.6: Appeler "read()" sur un fichier
   ZipFile fermé lève une erreur "ValueError". Précédemment, une
   erreur "RuntimeError" était levée.

ZipFile.testzip()

   Lit tous les fichiers de l'archive et vérifie leurs sommes CRC et
   leurs en-têtes. Retourne le nom du premier fichier mauvais ou
   retourne "None" sinon.

   Modifié dans la version 3.6: Calling "testzip()" on a closed
   ZipFile will raise a "ValueError".  Previously, a "RuntimeError"
   was raised.

ZipFile.write(filename, arcname=None, compress_type=None)

   Write the file named *filename* to the archive, giving it the
   archive name *arcname* (by default, this will be the same as
   *filename*, but without a drive letter and with leading path
   separators removed).  If given, *compress_type* overrides the value
   given for the *compression* parameter to the constructor for the
   new entry. The archive must be open with mode "'w'", "'x'" or
   "'a'".

   Note:

     Les noms d'archive doivent être relatifs à la racine de
     l'archive, c'est-à-dire qu'ils ne doivent pas commencer par un
     séparateur de chemin.

   Note:

     Si "arcname" (ou "filename" si "arcname" n'est pas donné)
     contient un octet nul, le nom du fichier dans l'archive sera
     tronqué à l'octet nul.

   Modifié dans la version 3.6: Appeler "write()" sur un fichier
   ZipFile fermé lève une erreur "ValueError". Précédemment, une
   erreur "RuntimeError" était levée.

ZipFile.writestr(zinfo_or_arcname, data[, compress_type])

   Write a file into the archive.  The contents is *data*, which may
   be either a "str" or a "bytes" instance; if it is a "str", it is
   encoded as UTF-8 first.  *zinfo_or_arcname* is either the file name
   it will be given in the archive, or a "ZipInfo" instance.  If it's
   an instance, at least the filename, date, and time must be given.
   If it's a name, the date and time is set to the current date and
   time. The archive must be opened with mode "'w'", "'x'" or "'a'".

   If given, *compress_type* overrides the value given for the
   *compression* parameter to the constructor for the new entry, or in
   the *zinfo_or_arcname* (if that is a "ZipInfo" instance).

   Note:

     Lorsque l'on passe une instance de "ZipInfo" dans le paramètre
     *zinfo_or_arcname*, la méthode de compression utilisée sera celle
     spécifiée dans le membre *compress_type* de l'instance "ZipInfo"
     donnée. Par défaut, le constructeur de la classe "ZipInfo"
     définit ce membre à "ZIP_STORED".

   Modifié dans la version 3.2: L'argument *compress_type*.

   Modifié dans la version 3.6: Appeler "writestr()" sur un fichier
   ZipFile fermé lève une erreur "ValueError". Précédemment, une
   erreur "RuntimeError" était levée.

Les attributs suivants sont aussi disponibles :

ZipFile.filename

   Nom du fichier ZIP.

ZipFile.debug

   Le niveau d'affichage de *debug* à utiliser. Peut être défini de
   "0" (par défaut, pas d'affichage) à "3" (affichage le plus bavard).
   Les informations de débogage sont affichées sur "sys.stdout".

ZipFile.comment

   The comment associated with the ZIP file as a "bytes" object. If
   assigning a comment to a "ZipFile" instance created with mode
   "'w'", "'x'" or "'a'", it should be no longer than 65535 bytes.
   Comments longer than this will be truncated.


13.5.2. Objets *PyZipFile*
==========================

Le constructeur de "PyZipFile" prend les mêmes paramètres que le
constructeur de "ZipFile" avec un paramètre additionnel *optimize*.

class zipfile.PyZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=True, optimize=-1)

   Nouveau dans la version 3.2: Le paramètre *optimize*.

   Modifié dans la version 3.4: Les extensions ZIP64 sont activées par
   défaut.

   Les instances ont une méthode supplémentaire par rapport aux objets
   "ZipFile" :

   writepy(pathname, basename='', filterfunc=None)

      Cherche les fichiers "*.py" et ajoute le fichier correspondant à
      l'archive.

      Si le paramètre *optimize* du constructeur de "PyZipFile" n'a
      pas été donné ou est à "-1", le fichier correspondant est un
      fichier "*.pyc", à compiler si nécessaire.

      Si le paramètre *optimize* du constructeur de "PyZipFile" est à
      "0", "1" ou "2", ne sont ajoutés dans l'archive que les fichiers
      avec ce niveau d'optimisation (voir "compile()"), à compiler si
      nécessaire.

      If *pathname* is a file, the filename must end with ".py", and
      just the (corresponding "*.pyc") file is added at the top level
      (no path information).  If *pathname* is a file that does not
      end with ".py", a "RuntimeError" will be raised.  If it is a
      directory, and the directory is not a package directory, then
      all the files "*.pyc" are added at the top level.  If the
      directory is a package directory, then all "*.pyc" are added
      under the package name as a file path, and if any subdirectories
      are package directories, all of these are added recursively.

      *basename* n'est sensé être utilisé qu'en interne.

      *filterfunc*, si donné, doit être une fonction prenant une seule
      chaîne de caractères en argument. Il lui sera passé chaque
      chemin (incluant chaque chemin de fichier complet individuel)
      avant d'être ajouté à l'archive. Si *filterfunc* retourne une
      valeur fausse, le chemin n'est pas ajouté et si c'est un
      répertoire son contenu est ignoré. Par exemple, si nos fichiers
      de test sont tous soit dans des répertoires "test" ou commencent
      par "test_", nous pouvons utiliser une fonction *filterfunc*
      pour les exclure :

         >>> zf = PyZipFile('myprog.zip')
         >>> def notests(s):
         ...     fn = os.path.basename(s)
         ...     return (not (fn == 'test' or fn.startswith('test_')))
         >>> zf.writepy('myprog', filterfunc=notests)

      La méthode "writepy()" crée des archives avec des noms de
      fichier comme suit :

         string.pyc                   # Top level name
         test/__init__.pyc            # Package directory
         test/testall.pyc             # Module test.testall
         test/bogus/__init__.pyc      # Subpackage directory
         test/bogus/myfile.pyc        # Submodule test.bogus.myfile

      Nouveau dans la version 3.4: Le paramètre *filterfunc*.

      Modifié dans la version 3.6.2: Le paramètre *pathname* accepte
      un objet chemin-compatible *path-like object*.


13.5.3. Objets *ZipInfo*
========================

Des instances de la classe "ZipInfo" sont retournées par les méthodes
"getinfo()" et "infolist()" des objets "ZipFile". Chaque objet stocke
des informations sur un seul membre de l'archive ZIP.

Il y a une méthode de classe pour créer une instance de "ZipInfo" pour
un fichier du système de fichiers :

classmethod ZipInfo.from_file(filename, arcname=None)

   Construit une instance de "ZipInfo" pour le fichier du système de
   fichiers, en préparation de l'ajouter à un fichier ZIP.

   *filename* doit être un chemin vers un fichier ou un répertoire
   dans le système de fichiers.

   Si *arcname* est spécifié, il est utilisé en tant que nom dans
   l'archive. Si *arcname* n'est pas spécifié, le nom sera le même que
   *filename* mais sans lettre de disque et sans séparateur de chemin
   en première position.

   Nouveau dans la version 3.6.

   Modifié dans la version 3.6.2: Le paramètre  *filename* accepte un
   objet chemin-compatible *path-like object*.

Les instances ont les méthodes et attributs suivants :

ZipInfo.is_dir()

   Retourne "True" si le membre d'archive est un répertoire.

   Utilise le nom de l'entrée : les répertoires doivent toujours se
   terminer par "/".

   Nouveau dans la version 3.6.

ZipInfo.filename

   Nom du fichier dans l'archive.

ZipInfo.date_time

   Date et heure de dernière modification pour le membre de l'archive.
   *Tuple* de six valeurs :

   +---------+----------------------------+
   | Index   | Valeur                     |
   |=========|============================|
   | "0"     | Année (>= 1980)            |
   +---------+----------------------------+
   | "1"     | Mois (indexé à partir de   |
   |         | 1)                         |
   +---------+----------------------------+
   | "2"     | Jour du mois (indexé à     |
   |         | partir de 1)               |
   +---------+----------------------------+
   | "3"     | Heures (indexées à partir  |
   |         | de 0)                      |
   +---------+----------------------------+
   | "4"     | Minutes (indexées à partir |
   |         | de 0)                      |
   +---------+----------------------------+
   | "5"     | Secondes (indexées à       |
   |         | partir de 0)               |
   +---------+----------------------------+

   Note:

     Le format de fichier ZIP ne gère pas les horodatages avant 1980.

ZipInfo.compress_type

   Type de compression du membre d'archive.

ZipInfo.comment

   Comment for the individual archive member as a "bytes" object.

ZipInfo.extra

   Expansion field data.  The PKZIP Application Note contains some
   comments on the internal structure of the data contained in this
   "bytes" object.

ZipInfo.create_system

   Système ayant créé l'archive ZIP.

ZipInfo.create_version

   Version de PKZIP ayant créé l'archive ZIP.

ZipInfo.extract_version

   Version de PKZIP nécessaire à l'extraction de l'archive ZIP.

ZipInfo.reserved

   Doit être à zéro.

ZipInfo.flag_bits

   Bits d'options ZIP.

ZipInfo.volume

   Numéro de volume de l'entête du fichier.

ZipInfo.internal_attr

   Attributs internes.

ZipInfo.external_attr

   Attributs de fichier externes.

ZipInfo.header_offset

   Longueur de l'entête du fichier en octets.

ZipInfo.CRC

   CRC-32 du fichier décompressé.

ZipInfo.compress_size

   Taille des données décompressées.

ZipInfo.file_size

   Taille du fichier décompressé.


13.5.4. Interface en ligne de commande
======================================

Le module "zipfile" fournit une interface en ligne de commande simple
pour interagir avec des archives ZIP.

Si vous voulez créer une nouvelle archive ZIP, spécifiez son nom après
l'option "-c" et listez ensuite le(s) nom(s) de fichier à inclure :

   $ python -m zipfile -c monty.zip spam.txt eggs.txt

Passer un répertoire est aussi possible :

   $ python -m zipfile -c monty.zip life-of-brian_1979/

Si vous voulez extraire une archive ZIP dans un répertoire donné,
utilisez l'option "-e" :

   $ python -m zipfile -e monty.zip target-dir/

Pour une liste des fichiers dans une archive ZIP, utilisez l'option
"-l" :

   $ python -m zipfile -l monty.zip


13.5.4.1. Options de la ligne de commande
-----------------------------------------

-l <zipfile>

   Liste les fichiers dans un fichier ZIP *zipfile*.

-c <zipfile> <source1> ... <sourceN>

   Crée un fichier ZIP *zipfile* à partir des fichiers *source*.

-e <zipfile> <output_dir>

   Extrait le fichier ZIP *zipfile* vers le répertoire cible
   *output_dir*.

-t <zipfile>

   Teste si le fichier zip est valide.
