web-dev-qa-db-fra.com

Extraire des fichiers de Zip sans conserver la structure en utilisant python ZipFile?

J'essaie d'extraire tous les fichiers de .Zip contenant des sous-dossiers dans un dossier. Je souhaite que tous les fichiers des sous-dossiers soient extraits dans un seul dossier sans conserver la structure d'origine. Pour le moment, je les extrait tous, déplace les fichiers dans un dossier, puis supprime les sous-dossiers précédents. Les fichiers portant le même nom sont écrasés.

Est-il possible de le faire avant d'écrire des fichiers?

Voici une structure par exemple:

my_Zip/file1.txt
my_Zip/dir1/file2.txt
my_Zip/dir1/dir2/file3.txt
my_Zip/dir3/file4.txt

À la fin, je souhaite ceci:

my_dir/file1.txt
my_dir/file2.txt
my_dir/file3.txt
my_dir/file4.txt

Que puis-je ajouter à ce code?

import zipfile
my_dir = "D:\\Download\\"
my_Zip = "D:\\Download\\my_file.Zip"

Zip_file = zipfile.ZipFile(my_Zip, 'r')
for files in Zip_file.namelist():
    Zip_file.extract(files, my_dir)
Zip_file.close()

si je renomme le chemin des fichiers de Zip_file.namelist (), j'ai cette erreur:

KeyError: "There is no item named 'file2.txt' in the archive"
36
Thammas

Cela ouvre les descripteurs de fichiers des membres de l’archive Zip, extrait le nom du fichier et le copie dans un fichier cible (c’est ainsi que ZipFile.extract fonctionne, sans se préoccuper des sous-répertoires).

import os
import shutil
import zipfile

my_dir = r"D:\Download"
my_Zip = r"D:\Download\my_file.Zip"

with zipfile.ZipFile(my_Zip) as Zip_file:
    for member in Zip_file.namelist():
        filename = os.path.basename(member)
        # skip directories
        if not filename:
            continue

        # copy file (taken from zipfile's extract)
        source = Zip_file.open(member)
        target = file(os.path.join(my_dir, filename), "wb")
        with source, target:
            shutil.copyfileobj(source, target)
46
Reiner Gerecke

Il est possible de parcourir la ZipFile.infolist(). Sur les objets ZipInfo retournés, vous pouvez ensuite manipuler filename pour supprimer la partie de répertoire et l'extraire dans un répertoire spécifié.

import glob
import zipfile
import shutil
import os

my_dir = "D:\\Download\\"
my_Zip = "D:\\Download\\my_file.Zip"

with zipfile.ZipFile(my_Zip) as Zip:
    for Zip_info in Zip.infolist():
        if Zip_info.filename[-1] == '/':
            continue
        Zip_info.filename = os.path.basename(Zip_info.filename)
        Zip.extract(Zip_info, my_dir)
8
Gerhard Götz

Extrayez simplement les octets en mémoire, calculez le nom du fichier et écrivez-le vous-même, Au lieu de laisser la bibliothèque le faire -, utilisez la méthode "read ()" au lieu de la méthode "extract ()":

import zipfile
import os

my_dir = "D:\\Download\\"
my_Zip = "D:\\Download\\my_file.Zip"

Zip_file = zipfile.ZipFile(my_Zip, 'r')
for files in Zip_file.namelist():
    data = Zip_file.read(files, my_dir)
    # I am almost shure Zip represents directory separator
    # char as "/" regardless of OS, but I  don't have DOS or Windos here to test it
    myfile_path = os.path.join(my_dir, files.split("/")[-1])
    myfile = open(myfile_path, "wb")
    myfile.write(data)
    myfile.close()
Zip_file.close()
8
jsbueno

Un concept similaire à la solution de Gerhard Götz , mais adapté pour extraire des fichiers uniques à la place de la totalité du Zip:

with ZipFile(zipPath, 'r') as zipObj:
    zipInfo = zipObj.getinfo(path_in_Zip))
    zipInfo.filename = os.path.basename(destination)
    zipObj.extract(zipInfo, os.path.dirname(os.path.realpath(destination)))
0
L0laapk3