Frage

Wie kann ich ein ZIP-Archiv mit einer Verzeichnisstruktur in Python erstellen?

War es hilfreich?

Lösung

Wie andere haben darauf hingewiesen, sollten Sie zipfile . Die Dokumentation sagt Ihnen, welche Funktionen zur Verfügung stehen, aber nicht wirklich erklären, wie Sie sie verwenden können ein ganzes Verzeichnis zip. Ich denke, es ist am einfachsten mit einigem Beispiel-Code zu erklären:

#!/usr/bin/env python
import os
import zipfile

def zipdir(path, ziph):
    # ziph is zipfile handle
    for root, dirs, files in os.walk(path):
        for file in files:
            ziph.write(os.path.join(root, file))

if __name__ == '__main__':
    zipf = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
    zipdir('tmp/', zipf)
    zipf.close()

Angepasst von: http://www.devshed.com/c/ a / Python / Python-entpackten /

Andere Tipps

Der einfachste Weg ist die Verwendung shutil.make_archive . Es unterstützt sowohl Reißverschluss und tar-Formate.

import shutil
shutil.make_archive(output_filename, 'zip', dir_name)

Wenn Sie etwas komplizierter als zippen das ganze Verzeichnis (wie das Überspringen bestimmter Dateien) tun müssen, dann müssen Sie in den zipfile Modul wie andere vorgeschlagen haben.

Um den Inhalt mydirectory auf eine neue Zip-Datei, einschließlich aller Dateien und Unterverzeichnisse hinzufügen:

import os
import zipfile

zf = zipfile.ZipFile("myzipfile.zip", "w")
for dirname, subdirs, files in os.walk("mydirectory"):
    zf.write(dirname)
    for filename in files:
        zf.write(os.path.join(dirname, filename))
zf.close()
  

Wie kann ich ein ZIP-Archiv mit einer Verzeichnisstruktur in Python erstellen?

In einem Python-Skript

In Python 2.7+, shutil hat eine make_archive Funktion.

from shutil import make_archive
make_archive(
  'zipfile_name', 
  'zip',           # the archive format - or tar, bztar, gztar 
  root_dir=None,   # root for archive - current working dir if None
  base_dir=None)   # start archiving from here - cwd if None too

Hier ist das Zip-Archiv wird den Namen zipfile_name.zip. Wenn base_dir ist weiter unten von root_dir wird es Dateien nicht in den base_dir ausschließen, sondern archivieren noch die Dateien in den übergeordneten Verzeichnissen bis zum root_dir.

habe ich die Prüfung dieses auf Cygwin mit 2.7 ein Problem haben - es will ein ROOT_DIR Argument, für cwd:

make_archive('zipfile_name', 'zip', root_dir='.')

Verwenden von Python aus der Shell

Sie können diese von der Shell mit Python tun auch die zipfile Modul mit:

$ python -m zipfile -c zipname sourcedir

Wo zipname der Name der Zieldatei Sie (fügen .zip, wenn Sie es wünschen, wird es nicht automatisch tun) wollen und sourcedir ist der Pfad zu dem Verzeichnis.

Python Zipping (oder einfach nicht Elternverzeichnis wollen):

Wenn Sie versuchen, ein Python-Paket mit einem __init__.py und __main__.py zip, und Sie nicht möchten, dass das übergeordnete Verzeichnis, es ist

$ python -m zipfile -c zipname sourcedir/*

Und

$ python zipname

würde das Paket ausführen. (Beachten Sie, dass Sie nicht Subpackages als Einstiegspunkt aus einem ZIP-Archiv ausführen können.)

Python-app Zipping:

Wenn Sie python3.5 + haben, und wollen speziell ein Python-Paket zip, verwenden Sie zipapp :

$ python -m zipapp myapp
$ python myapp.pyz

Diese Funktion rekursiv einen Verzeichnisbaum zip wird, Komprimieren die Dateien und die richtigen relativen Dateinamen im Archiv gespeichert werden. Die Archiveinträge sind die gleichen wie diejenigen, die durch zip -r output.zip source_dir.

import os
import zipfile
def make_zipfile(output_filename, source_dir):
    relroot = os.path.abspath(os.path.join(source_dir, os.pardir))
    with zipfile.ZipFile(output_filename, "w", zipfile.ZIP_DEFLATED) as zip:
        for root, dirs, files in os.walk(source_dir):
            # add directory (needed for empty dirs)
            zip.write(root, os.path.relpath(root, relroot))
            for file in files:
                filename = os.path.join(root, file)
                if os.path.isfile(filename): # regular files only
                    arcname = os.path.join(os.path.relpath(root, relroot), file)
                    zip.write(filename, arcname)

Mit shutil, dem Teil der Python-Standardbibliothek ist. Mit shutil so einfach ist (siehe Code unten):

  • 1. arg: Dateiname der resultierenden zip / tar-Datei,
  • 2. arg: PLZ / Teer,
  • 3. arg: dir_name

Code:

import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')

Für Kompression auf die resultierenden ZIP-Datei hinzufügen, Check-out Link .

Sie müssen sich ändern:

zip = zipfile.ZipFile('Python.zip', 'w')

zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)

Ich habe einige Änderungen an Code gegeben von Mark Byers gemacht. Im Folgenden Funktion wird fügt auch leere Verzeichnisse, wenn Sie sie haben. Beispiele sollten es machen klar, was der Pfad zu dem Reißverschluss.

hinzugefügt ist
#!/usr/bin/env python
import os
import zipfile

def addDirToZip(zipHandle, path, basePath=""):
    """
    Adding directory given by \a path to opened zip file \a zipHandle

    @param basePath path that will be removed from \a path when adding to archive

    Examples:
        # add whole "dir" to "test.zip" (when you open "test.zip" you will see only "dir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir')
        zipHandle.close()

        # add contents of "dir" to "test.zip" (when you open "test.zip" you will see only it's contents)
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir', 'dir')
        zipHandle.close()

        # add contents of "dir/subdir" to "test.zip" (when you open "test.zip" you will see only contents of "subdir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir/subdir', 'dir/subdir')
        zipHandle.close()

        # add whole "dir/subdir" to "test.zip" (when you open "test.zip" you will see only "subdir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir/subdir', 'dir')
        zipHandle.close()

        # add whole "dir/subdir" with full path to "test.zip" (when you open "test.zip" you will see only "dir" and inside it only "subdir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir/subdir')
        zipHandle.close()

        # add whole "dir" and "otherDir" (with full path) to "test.zip" (when you open "test.zip" you will see only "dir" and "otherDir")
        zipHandle = zipfile.ZipFile('test.zip', 'w')
        addDirToZip(zipHandle, 'dir')
        addDirToZip(zipHandle, 'otherDir')
        zipHandle.close()
    """
    basePath = basePath.rstrip("\\/") + ""
    basePath = basePath.rstrip("\\/")
    for root, dirs, files in os.walk(path):
        # add dir itself (needed for empty dirs
        zipHandle.write(os.path.join(root, "."))
        # add files
        for file in files:
            filePath = os.path.join(root, file)
            inZipPath = filePath.replace(basePath, "", 1).lstrip("\\/")
            #print filePath + " , " + inZipPath
            zipHandle.write(filePath, inZipPath)

Oben ist eine einfache Funktion, die für einfache Fälle funktionieren soll. Sie können elegantere Klasse in meinem Gist finden: https://gist.github.com/Eccenux/17526123107ca0ac28e6

Sie wollen wahrscheinlich am zipfile Modul suchen; gibt es Dokumentation unter http://docs.python.org/library/zipfile.html .

Sie auch os.walk() die Verzeichnisstruktur zu indizieren möchten.

Ich habe ein anderes Codebeispiel, das unter Verwendung von python3, pathlib und zipfile kann helfen. Es sollte in jedem Betriebssystem arbeiten.

from pathlib import Path
import zipfile
from datetime import datetime

DATE_FORMAT = '%y%m%d'


def date_str():
    """returns the today string year, month, day"""
    return '{}'.format(datetime.now().strftime(DATE_FORMAT))


def zip_name(path):
    """returns the zip filename as string"""
    cur_dir = Path(path).resolve()
    parent_dir = cur_dir.parents[0]
    zip_filename = '{}/{}_{}.zip'.format(parent_dir, cur_dir.name, date_str())
    p_zip = Path(zip_filename)
    n = 1
    while p_zip.exists():
        zip_filename = ('{}/{}_{}_{}.zip'.format(parent_dir, cur_dir.name,
                                             date_str(), n))
        p_zip = Path(zip_filename)
        n += 1
    return zip_filename


def all_files(path):
    """iterator returns all files and folders from path as absolute path string
    """
    for child in Path(path).iterdir():
        yield str(child)
        if child.is_dir():
            for grand_child in all_files(str(child)):
                yield str(Path(grand_child))


def zip_dir(path):
    """generate a zip"""
    zip_filename = zip_name(path)
    zip_file = zipfile.ZipFile(zip_filename, 'w')
    print('create:', zip_filename)
    for file in all_files(path):
        print('adding... ', file)
        zip_file.write(file)
    zip_file.close()


if __name__ == '__main__':
    zip_dir('.')
    print('end!')

Hier ist eine Variation auf die Antwort von Nux gegeben, die für mich funktioniert:

def WriteDirectoryToZipFile( zipHandle, srcPath, zipLocalPath = "", zipOperation = zipfile.ZIP_DEFLATED ):
    basePath = os.path.split( srcPath )[ 0 ]
    for root, dirs, files in os.walk( srcPath ):
        p = os.path.join( zipLocalPath, root [ ( len( basePath ) + 1 ) : ] )
        # add dir
        zipHandle.write( root, p, zipOperation )
        # add files
        for f in files:
            filePath = os.path.join( root, f )
            fileInZipPath = os.path.join( p, f )
            zipHandle.write( filePath, fileInZipPath, zipOperation )

Versuchen Sie, die unter einer .it für mich gearbeitet .

import zipfile, os
zipf = "compress.zip"  
def main():
    directory = r"Filepath"
    toZip(directory)
def toZip(directory):
    zippedHelp = zipfile.ZipFile(zipf, "w", compression=zipfile.ZIP_DEFLATED )

    list = os.listdir(directory)
    for file_list in list:
        file_name = os.path.join(directory,file_list)

        if os.path.isfile(file_name):
            print file_name
            zippedHelp.write(file_name)
        else:
            addFolderToZip(zippedHelp,file_list,directory)
            print "---------------Directory Found-----------------------"
    zippedHelp.close()

def addFolderToZip(zippedHelp,folder,directory):
    path=os.path.join(directory,folder)
    print path
    file_list=os.listdir(path)
    for file_name in file_list:
        file_path=os.path.join(path,file_name)
        if os.path.isfile(file_path):
            zippedHelp.write(file_path)
        elif os.path.isdir(file_name):
            print "------------------sub directory found--------------------"
            addFolderToZip(zippedHelp,file_name,path)


if __name__=="__main__":
    main()

Wenn Sie eine Funktionalität wie die Kompresse Ordner einer gemeinsamen grafischen Dateimanager möchten Sie den folgenden Code verwenden kann, verwendet es die zipfile Modul. mit diesem Code werden Sie die ZIP-Datei mit dem Pfad als Stammordner.

import os
import zipfile

def zipdir(path, ziph):
    # Iterate all the directories and files
    for root, dirs, files in os.walk(path):
        # Create a prefix variable with the folder structure inside the path folder. 
        # So if a file is at the path directory will be at the root directory of the zip file
        # so the prefix will be empty. If the file belongs to a containing folder of path folder 
        # then the prefix will be that folder.
        if root.replace(path,'') == '':
                prefix = ''
        else:
                # Keep the folder structure after the path folder, append a '/' at the end 
                # and remome the first character, if it is a '/' in order to have a path like 
                # folder1/folder2/file.txt
                prefix = root.replace(path, '') + '/'
                if (prefix[0] == '/'):
                        prefix = prefix[1:]
        for filename in files:
                actual_file_path = root + '/' + filename
                zipped_file_path = prefix + filename
                zipf.write( actual_file_path, zipped_file_path)


zipf = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
zipdir('/tmp/justtest/', zipf)
zipf.close()

Moderne Python (3.6+) mit dem pathlib Modul für kurze OOP -ähnlichen Handhabung von Pfaden und pathlib.Path.rglob() für rekursive Globbing. Soweit ich das beurteilen kann, ist dies gleichbedeutend mit George V. Reilly Antwort: Reißverschluss mit Kompression, das oberste Element ein Verzeichnis ist, hält leer dirs, verwendet relative Pfade.

from pathlib import Path
from zipfile import ZIP_DEFLATED, ZipFile

from os import PathLike
from typing import Union


def zip_dir(zip_name: str, source_dir: Union[str, PathLike]):
    src_path = Path(source_dir).expanduser().resolve(strict=True)
    with ZipFile(zip_name, 'w', ZIP_DEFLATED) as zf:
        for file in src_path.rglob('*'):
            zf.write(file, file.relative_to(src_path.parent))

Hinweis: als optionaler Typ Hinweise zeigen, zip_name keine Path-Objekt sein kann ( würde in 3.6 festgelegt werden. 2+ ).

mehr Flexibilität geben, z.B. Wählen Sie Verzeichnis / Datei mit Namen verwenden:

import os
import zipfile

def zipall(ob, path, rel=""):
    basename = os.path.basename(path)
    if os.path.isdir(path):
        if rel == "":
            rel = basename
        ob.write(path, os.path.join(rel))
        for root, dirs, files in os.walk(path):
            for d in dirs:
                zipall(ob, os.path.join(root, d), os.path.join(rel, d))
            for f in files:
                ob.write(os.path.join(root, f), os.path.join(rel, f))
            break
    elif os.path.isfile(path):
        ob.write(path, os.path.join(rel, basename))
    else:
        pass

Für einen Dateibaum:

.
├── dir
│   ├── dir2
│   │   └── file2.txt
│   ├── dir3
│   │   └── file3.txt
│   └── file.txt
├── dir4
│   ├── dir5
│   └── file4.txt
├── listdir.zip
├── main.py
├── root.txt
└── selective.zip

Sie können zum Beispiel Wählen Sie nur dir4 und root.txt:

cwd = os.getcwd()
files = [os.path.join(cwd, f) for f in ['dir4', 'root.txt']]

with zipfile.ZipFile("selective.zip", "w" ) as myzip:
    for f in files:
        zipall(myzip, f)

oder listdir nur in Skriptaufruf Verzeichnis und fügen Sie alles von dort aus:

with zipfile.ZipFile("listdir.zip", "w" ) as myzip:
    for f in os.listdir():
        if f == "listdir.zip":
            # Creating a listdir.zip in the same directory
            # will include listdir.zip inside itself, beware of this
            continue
        zipall(myzip, f)

Angenommen, Sie alle Ordner (Unterverzeichnisse) im aktuellen Verzeichnis Zip wollen.

for root, dirs, files in os.walk("."):
    for sub_dir in dirs:
        zip_you_want = sub_dir+".zip"
        zip_process = zipfile.ZipFile(zip_you_want, "w", zipfile.ZIP_DEFLATED)
        zip_process.write(file_you_want_to_include)
        zip_process.close()

        print("Successfully zipped directory: {sub_dir}".format(sub_dir=sub_dir))

Hier ist ein moderner Ansatz, mit pathlib und ein Kontext-Manager. Versetzt die Dateien direkt in der ZIP, anstatt in einem Unterordner.

def zip_dir(filename: str, dir_to_zip: pathlib.Path):
    with zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) as zipf:
        # Use glob instead of iterdir(), to cover all subdirectories.
        for directory in dir_to_zip.glob('**'):
            for file in directory.iterdir():
                if not file.is_file():
                    continue
                # Strip the first component, so we don't create an uneeded subdirectory
                # containing everything.
                zip_path = pathlib.Path(*file.parts[1:])
                # Use a string, since zipfile doesn't support pathlib  directly.
                zipf.write(str(file), str(zip_path))

bereitete ich eine Funktion von Mark Byers' Lösung mit Reimund und Morten Zilmer der Konsolidierung Kommentare (relative Pfad und auch leere Verzeichnisse). Als bewährte Methode ist, with in ZipFile Datei Konstruktion.

Die Funktion bereitet auch einen Standard-Zip-Datei-Namen mit den Zip-Verzeichnisnamen und ‚.zip‘ Erweiterung. Deshalb funktioniert es nur mit einem Argument:. Das Quellverzeichnis zu Einzippen

import os
import zipfile

def zip_dir(path_dir, path_file_zip=''):
if not path_file_zip:
    path_file_zip = os.path.join(
        os.path.dirname(path_dir), os.path.basename(path_dir)+'.zip')
with zipfile.ZipFile(path_file_zip, 'wb', zipfile.ZIP_DEFLATED) as zip_file:
    for root, dirs, files in os.walk(path_dir):
        for file_or_dir in files + dirs:
            zip_file.write(
                os.path.join(root, file_or_dir),
                os.path.relpath(os.path.join(root, file_or_dir),
                                os.path.join(path_dir, os.path.pardir)))
# import required python modules
# You have to install zipfile package using pip install

import os,zipfile

# Change the directory where you want your new zip file to be

os.chdir('Type your destination')

# Create a new zipfile ( I called it myfile )

zf = zipfile.ZipFile('myfile.zip','w')

# os.walk gives a directory tree. Access the files using a for loop

for dirnames,folders,files in os.walk('Type your directory'):
    zf.write('Type your Directory')
    for file in files:
        zf.write(os.path.join('Type your directory',file))

Nun, nach den Vorschlägen Lesen kam ich mit einem sehr ähnlichen Weg nach oben, die mit 2.7.x arbeitet ohne „funny“ Verzeichnisnamen zu schaffen (absolut artige Namen), und nur die angegebenen Ordner innerhalb der ZIP erstellen.

Oder nur, wenn Sie benötigen, um Ihre Zip-Ordner nach innen mit dem Inhalt des ausgewählten Verzeichnisses enthalten.

def zipDir( path, ziph ) :
 """
 Inserts directory (path) into zipfile instance (ziph)
 """
 for root, dirs, files in os.walk( path ) :
  for file in files :
   ziph.write( os.path.join( root, file ) , os.path.basename( os.path.normpath( path ) ) + "\\" + file )

def makeZip( pathToFolder ) :
 """
 Creates a zip file with the specified folder
 """
 zipf = zipfile.ZipFile( pathToFolder + 'file.zip', 'w', zipfile.ZIP_DEFLATED )
 zipDir( pathToFolder, zipf )
 zipf.close()
 print( "Zip file saved to: " + pathToFolder)

makeZip( "c:\\path\\to\\folder\\to\\insert\\into\\zipfile" )

Funktion zip-Datei zu erstellen.

def CREATEZIPFILE(zipname, path):
    #function to create a zip file
    #Parameters: zipname - name of the zip file; path - name of folder/file to be put in zip file

    zipf = zipfile.ZipFile(zipname, 'w', zipfile.ZIP_DEFLATED)
    zipf.setpassword(b"password") #if you want to set password to zipfile

    #checks if the path is file or directory
    if os.path.isdir(path):
        for files in os.listdir(path):
            zipf.write(os.path.join(path, files), files)

    elif os.path.isfile(path):
        zipf.write(os.path.join(path), path)
    zipf.close()

Für einen kurzer Weg, um die Ordner-Hierarchie unter dem übergeordneten Verzeichnis beibehalten werden archiviert:

import glob
import zipfile

with zipfile.ZipFile(fp_zip, "w", zipfile.ZIP_DEFLATED) as zipf:
    for fp in glob(os.path.join(parent, "**/*")):
        base = os.path.commonpath([parent, fp])
        zipf.write(fp, arcname=fp.replace(base, ""))

Wenn Sie möchten, könnten Sie dies ändern pathlib für Datei verwenden Globbing .

So viele Antworten hier, und ich hoffe, dass ich mit meiner eigenen Version beitragen könnte, die auf der ursprünglichen Antwort basieren (übrigens), aber mit einer grafischen Sicht auch für jeden zipfile Setup mit Kontext und Sortierung os.walk(), um eine geordnete Ausgabe zu haben.

diese Ordner und diese Dateien zu haben (unter anderen Ordnern), wollte ich einen .zip für jeden cap_ Ordner erstellen:

$ tree -d
.
├── cap_01
|    ├── 0101000001.json
|    ├── 0101000002.json
|    ├── 0101000003.json
|
├── cap_02
|    ├── 0201000001.json
|    ├── 0201000002.json
|    ├── 0201001003.json
|
├── cap_03
|    ├── 0301000001.json
|    ├── 0301000002.json
|    ├── 0301000003.json
| 
├── docs
|    ├── map.txt
|    ├── main_data.xml
|
├── core_files
     ├── core_master
     ├── core_slave

Hier ist, was ich angewandt, mit Kommentaren zum besseren Verständnis des Prozesses.

$ cat zip_cap_dirs.py 
""" Zip 'cap_*' directories. """           
import os                                                                       
import zipfile as zf                                                            


for root, dirs, files in sorted(os.walk('.')):                                                                                               
    if 'cap_' in root:                                                          
        print(f"Compressing: {root}")                                           
        # Defining .zip name, according to Capítulo.                            
        cap_dir_zip = '{}.zip'.format(root)                                     
        # Opening zipfile context for current root dir.                         
        with zf.ZipFile(cap_dir_zip, 'w', zf.ZIP_DEFLATED) as new_zip:          
            # Iterating over os.walk list of files for the current root dir.    
            for f in files:                                                     
                # Defining relative path to files from current root dir.        
                f_path = os.path.join(root, f)                                  
                # Writing the file on the .zip file of the context              
                new_zip.write(f_path) 

Im Grunde genommen für jede Iteration über os.walk(path), ich bin einen Kontext für zipfile Setup zu öffnen und danach, Iterieren über files laufen, die eine list von Dateien aus root Verzeichnis, bezogen den relativen Pfad für jede Datei bilden, auf dem aktuellen root Verzeichnis, das Anhängen an den zipfile Kontext, der ausgeführt wird.

Und die Ausgabe wird wie folgt dargestellt:

$ python3 zip_cap_dirs.py
Compressing: ./cap_01
Compressing: ./cap_02
Compressing: ./cap_03

Um den Inhalt jedes .zip Verzeichnis zu sehen, können Sie less Befehl:

$ less cap_01.zip

Archive:  cap_01.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
  22017  Defl:N     2471  89% 2019-09-05 08:05 7a3b5ec6  cap_01/0101000001.json
  21998  Defl:N     2471  89% 2019-09-05 08:05 155bece7  cap_01/0101000002.json
  23236  Defl:N     2573  89% 2019-09-05 08:05 55fced20  cap_01/0101000003.json
--------          ------- ---                           -------
  67251             7515  89%                            3 files
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top