it-swarm.com.de

Hinzufügen von Ordnern zu einer ZIP-Datei mit Python

Ich möchte eine Zip-Datei erstellen. Fügen Sie der Zip-Datei einen Ordner hinzu und fügen Sie diesem Ordner dann eine Reihe von Dateien hinzu.

Ich möchte also eine ZIP-Datei mit einem einzigen Ordner mit Dateien erstellen.

Ich weiß nicht, ob es schlechte Praxis ist, Ordner in Zip-Dateien zu haben oder so, aber Google gibt mir zu diesem Thema nichts.

Ich habe damit angefangen:

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

Aus: http://mail.python.org/pipermail/python-list/2006-August/396166.html

Dadurch werden alle Ordner entfernt und alle Dateien im Zielordner (und seinen Unterordnern) in einer einzigen ZIP-Datei gespeichert. Ich konnte nicht einen ganzen Ordner hinzufügen.

Wenn ich den Pfad in einen Ordner in myZipFile.write einfüge, bekomme ich

IOError: [Errno 13] Berechtigung abgelehnt: '..\package\bin'

Jede Hilfe ist sehr willkommen.

Zugehörige Frage: Wie kann ich den Inhalt eines Ordners mit Python (Version 2.5) komprimieren?

40
Mizipzor

Ok, nachdem ich verstanden habe, was Sie wollen, ist es so einfach wie das zweite Argument von zipfile.write, wo Sie alles verwenden können, was Sie wollen:

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

erstellt eine zip-Datei, in der test.py in ein Verzeichnis namens dir extrahiert wird. 

BEARBEITEN: Ich musste einmal ein leeres Verzeichnis in einer ZIP-Datei erstellen: Es ist möglich, dass nach dem obigen Code die Datei test.py aus der ZIP-Datei gelöscht wird. Die Datei ist nicht mehr vorhanden, das leere Verzeichnis bleibt jedoch erhalten .

44
RSabet

Sie können auch shutil verwenden

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)

Dadurch wird der gesamte Ordner in die ZIP-Datei eingefügt.

50
Gideon

Eine Zip-Datei hat keine Verzeichnisstruktur, sie enthält nur eine Reihe von Pfadnamen und deren Inhalt. Diese Pfadnamen sollten relativ zu einem imaginären Stammordner (der ZIP-Datei selbst) sein. "../" -Präfixe haben in einer Zip-Datei keine definierte Bedeutung.

Stellen Sie sich vor, Sie haben eine Datei, a, und Sie möchten sie in einem "Ordner" in einer Zip-Datei speichern. Sie müssen dem Dateinamen lediglich einen Ordnernamen voranstellen, wenn Sie die Datei in der zip-Datei speichern:

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

Ich kenne keine Zip-Implementierungen, die die Aufnahme eines empty -Ordners in eine Zip-Datei erlauben. Ich kann mir eine Problemumgehung vorstellen (das Speichern eines dummy dateinamens im Zip-Ordner, der bei der Extraktion ignoriert werden sollte), aber nicht portabel über Implementierungen hinweg.

12
tzot
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()

Ich renne:

python tozip.py

Dies ist das Protokoll:

[email protected]:~$ 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)

Wie Sie sehen können, ist das Archiv auch in Ordnung. Dies ist eine rekursive Funktion, die einen ganzen Ordner komprimieren kann. Das einzige Problem ist, dass kein leerer Ordner erstellt wird.

Prost.

8
havok-cr

Nachstehend finden Sie einige Codes zum Zippen eines gesamten Verzeichnisses in eine ZIP-Datei.

Dies scheint in Ordnung zu sein, wenn Sie Zip-Dateien unter Windows und Linux erstellen. Die Ausgangsdateien () Scheinen unter Windows (eingebaute Compressed Folders-Funktion, WinZip und 7-Zip) und Linux ordnungsgemäß zu extrahieren. Leere Verzeichnisse in einer ZIP-Datei werden jedoch angezeigt Dies ist ein heikles Problem. Die Lösung scheint zu funktionieren, aber die Ausgabe von "Zipinfo" unter Linux ist besorgniserregend. Außerdem werden die Verzeichnisberechtigungen nicht korrekt für leere Verzeichnisse im Zip-Archiv festgelegt. Dies scheint etwas eingehender Forschung zu erfordern.

Ich habe einige Informationen von diesem Velocity Reviews Thread und diesem Python Mailing List Thread erhalten.

Beachten Sie, dass diese Funktion dazu dient, Dateien mit Entweder keinem übergeordneten Verzeichnis oder nur einem übergeordneten Verzeichnis im Zip-Archiv abzulegen. Alle führenden Verzeichnisse in den Dateisystempfaden werden beschnitten und nicht in das .__ eingeschlossen. Zip-Archivpfade. Dies ist im Allgemeinen der Fall, wenn Sie ein directory in eine ZIP-Datei umwandeln möchten, die an verschiedenen -Speicherorten extrahiert werden kann. 

Keyword-Argumente:

dirPath - String-Pfad zum zu archivierenden Verzeichnis. Dies ist das einzige erforderliche Argument. Es kann absolut oder relativ sein, aber nur ein oder null Führende Verzeichnisse werden in das Zip-Archiv aufgenommen.

zipFilePath - String-Pfad zur Zip-Ausgabedatei. Dies kann ein absoluter Pfad oder ein relativer Pfad sein. Wenn die ZIP-Datei bereits vorhanden ist, wird sie aktualisiert. Wenn Nicht, wird es erstellt. Wenn Sie es von Grund auf ersetzen möchten, löschen Sie es , Bevor Sie diese Funktion aufrufen. (Standardwert wird als dirPath + ".Zip" berechnet)

includeDirInZip - boolean gibt an, ob das Verzeichnis der obersten Ebene im Archiv enthalten oder weggelassen werden soll. (default True)

(Beachten Sie, dass StackOverflow den Python scheinbar nicht mit Triple-Strings ausgeben kann, daher habe ich meine Doc-Strings hier in den Posttext konvertiert.)

#!/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()

Hier sind einige Beispielanwendungen. Wenn Ihr dirPath-Argument mehrere führende Verzeichnisse enthält, wird standardmäßig nur das LETZTE Verzeichnis hinzugefügt. Übergeben Sie includeDirInZip = False, um alle führenden Verzeichnisse wegzulassen.

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")
4
Peter Lyons

hier ist meine Funktion, die ich zum Zip eines Ordners verwende:

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()
3
Dmitry Nedbaylo

Wenn Sie sich eine mit Info-Zip erstellte Zip-Datei ansehen, werden Sie feststellen, dass Verzeichnisse tatsächlich aufgelistet sind:

$ 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

Beachten Sie, dass der Verzeichniseintrag null Länge hat und nicht komprimiert ist. Es scheint, dass Sie mit Python dasselbe erreichen können, indem Sie das Verzeichnis nach Namen schreiben, es jedoch zwingen, keine Komprimierung zu verwenden.

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)

Es kann sich lohnen, sicherzustellen, dass arcname in einem / endet.

2
z0r

nachdem Sie einige Importe hinzugefügt haben, läuft Ihr Code für mich einwandfrei. Wie nennen Sie das Skript? 

Ich habe Ihren Code mit den folgenden Argumenten aufgerufen:

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

`

2
RSabet

Vielen Dank für diese nützliche Funktion! Ich fand es sehr nützlich, da ich auch nach Hilfe suchte. Vielleicht wäre es jedoch sinnvoll, es ein wenig zu ändern 

basedir = os.path.dirname(dirpath) + '/'

wäre 

basedir = os.path.dirname(dirpath + '/')

Wenn ich herausfand, dass der Ordner "Example", der sich unter "C:\Ordner\Pfad\NotWanted\in\Zip\Example" befindet, gepackt werden soll,

Ich habe in Windows:

dirpath = 'C:\folder\path\notWanted\to\Zip\Example'
basedir = 'C:\folder\path\notWanted\to\Zip\Example/'
dirname = 'C:\folder\path\notWanted\to\Zip\Example\Example\Subfolder_etc'

Aber ich nehme an, dein Code sollte geben

dirpath = 'C:\folder\path\notWanted\to\Zip\Example'
basedir = 'C:\folder\path\notWanted\to\Zip\Example\'
dirname = '\Subfolder_etc'
0
note
import os
import zipfile

zf = zipfile.ZipFile("file.Zip", "w")
for file in os.listdir(os.curdir):
    if not file.endswith('.Zip') and os.path.isfile(os.curdir+'/'+file):
        print file
        zf.write(file)
    Elif os.path.isdir(os.curdir+'/'+file):
        print f
        for f in os.listdir(os.curdir+'/'+file):
            zf.write(file+'\\'+f)
zf.close()
0
sohom

Hier ist der bearbeitete Code, den ich lief. Es basiert auf dem Code oben, der Mailingliste entnommen. Ich habe die Importe hinzugefügt und eine Hauptroutine gemacht. Ich habe auch das Fummeln mit dem Ausgabedateinamen herausgeschnitten, um den Code zu verkürzen.

#!/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])

Bei der Arbeit, in meinem Windows-Feld, lief dieser Code einwandfrei, aber er erstellte keine "Ordner" in der ZIP-Datei. Zumindest erinnere ich mich daran. Zuhause, auf meiner Linux-Box, scheint die erstellte Zip-Datei schlecht zu sein:

$ 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.

Ich weiß nicht, ob ich versehentlich den Code gebrochen habe, ich denke, es ist dasselbe. Plattformübergreifende Probleme? Wie auch immer, es hat nichts mit meiner ursprünglichen Frage zu tun; Ordner in der Zip-Datei abrufen. Ich wollte nur den Code veröffentlichen, den ich tatsächlich lief, nicht den Code, auf dem ich meinen Code basiert.

0
Mizipzor