Antworten:
Wie andere bereits betont haben, sollten Sie zipfile verwenden . In der Dokumentation erfahren Sie, welche Funktionen verfügbar sind, es wird jedoch nicht erläutert, wie Sie damit ein gesamtes Verzeichnis komprimieren können. Ich denke, es ist am einfachsten, mit einem Beispielcode 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-UnZipped/
os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))
. Auf diese Weise können Sie ein Verzeichnis aus einem beliebigen Arbeitsverzeichnis komprimieren, ohne die vollständigen absoluten Pfade im Archiv abzurufen.
shutil
macht es wirklich einfach in nur einer Zeile. Bitte überprüfen Sie die Antwort unten ..
.close()
Anruf verpasst !
Der einfachste Weg ist zu verwenden shutil.make_archive
. Es unterstützt sowohl Zip- als auch Teerformate.
import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
Wenn Sie etwas Komplizierteres tun müssen, als das gesamte Verzeichnis zu komprimieren (z. B. bestimmte Dateien zu überspringen), müssen Sie sich zipfile
wie von anderen vorgeschlagen in das Modul vertiefen .
shutil
ist Teil der Standard-Python-Bibliothek. Dies sollte die beste Antwort sein
shutil.make_archive
verwendet wird os.chdir()
. Nach dem, worüber ich lese os.chdir()
, ist es global tätig.
So fügen Sie den Inhalt mydirectory
einer neuen Zip-Datei hinzu, einschließlich aller Dateien und Unterverzeichnisse:
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()
with
anstatt close()
dich am Ende selbst anrufen zu müssen?
Wie kann ich ein Zip-Archiv einer Verzeichnisstruktur in Python erstellen?
Hat in Python 2.7+ shutil
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 wird das komprimierte Archiv benannt zipfile_name.zip
. Wenn base_dir
es weiter unten root_dir
liegt, werden Dateien ausgeschlossen, die sich nicht in der befinden base_dir
, aber dennoch die Dateien in den übergeordneten Verzeichnissen bis zum archivieren root_dir
.
Ich hatte ein Problem beim Testen auf Cygwin mit 2.7 - es möchte ein root_dir-Argument für cwd:
make_archive('zipfile_name', 'zip', root_dir='.')
Sie können dies mit Python aus der Shell auch mit dem zipfile
Modul tun :
$ python -m zipfile -c zipname sourcedir
Wo zipname
ist der Name der gewünschten .zip
Zieldatei (hinzufügen, wenn Sie es wollen, wird es nicht automatisch tun) und Sourcedir ist der Pfad zum Verzeichnis.
Wenn Sie versuchen, ein Python-Paket mit einem __init__.py
und zu komprimieren __main__.py
, und Sie das übergeordnete Verzeichnis nicht möchten, ist dies der Fall
$ python -m zipfile -c zipname sourcedir/*
Und
$ python zipname
würde das Paket ausführen. (Beachten Sie, dass Sie keine Unterpakete als Einstiegspunkt aus einem komprimierten Archiv ausführen können.)
Wenn Sie Python3.5 + haben und speziell ein Python-Paket komprimieren möchten, verwenden Sie zipapp :
$ python -m zipapp myapp
$ python myapp.pyz
Diese Funktion komprimiert rekursiv einen Verzeichnisbaum, komprimiert die Dateien und zeichnet die korrekten relativen Dateinamen im Archiv auf. Die Archiveinträge sind die gleichen wie die von 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)
Verwenden Sie shutil, das Teil des Python-Standardbibliothekssatzes ist. Die Verwendung von shutil ist so einfach (siehe Code unten):
Code:
import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
Überprüfen Sie diesen Link , um der resultierenden Zip-Datei eine Komprimierung hinzuzufügen .
Du musst dich ändern:
zip = zipfile.ZipFile('Python.zip', 'w')
zu
zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
Ich habe einige Änderungen am Code von Mark Byers vorgenommen . Die folgende Funktion fügt auch leere Verzeichnisse hinzu, wenn Sie diese haben. Beispiele sollten klarer machen, welcher Pfad der Zip hinzugefügt wird.
#!/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 sollte. Eine elegantere Klasse finden Sie in meinem Gist: https://gist.github.com/Eccenux/17526123107ca0ac28e6
Modernes Python (3.6+) verwendet das pathlib
Modul zur präzisen OOP-ähnlichen Behandlung von Pfaden und pathlib.Path.rglob()
zum rekursiven Globbing. Soweit ich das beurteilen kann, entspricht dies der Antwort von George V. Reilly: Zips mit Komprimierung, das oberste Element ist ein Verzeichnis, hält leere Verzeichnisse, 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: Wie optionale Typhinweise anzeigen, zip_name
kann es sich nicht um ein Pfadobjekt handeln (wird in 3.6.2+ behoben ).
Ich habe ein anderes Codebeispiel, das mit Python3, Pathlib und Zipfile helfen kann. Es sollte in jedem Betriebssystem funktionieren.
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!')
Sie möchten sich wahrscheinlich das zipfile
Modul ansehen . Eine Dokumentation finden Sie unter http://docs.python.org/library/zipfile.html .
Möglicherweise möchten Sie auch die os.walk()
Verzeichnisstruktur indizieren.
Hier ist eine Variation der Antwort von Nux, 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 )
Probieren Sie die folgende aus. Es hat bei mir funktioniert .
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 den Komprimierungsordner eines gängigen grafischen Dateimanagers wünschen, können Sie den folgenden Code verwenden, er verwendet das zipfile- Modul. Mit diesem Code haben 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()
Um mehr Flexibilität zu bieten, z. B. Verzeichnis / Datei nach Namen auswählen, verwenden Sie:
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 zB nur auswählen 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 einfach listdir
im Skriptaufrufverzeichnis und fügen Sie alles von dort hinzu:
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 möchten alle Ordner (Unterverzeichnisse) im aktuellen Verzeichnis komprimieren.
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))
So behalten Sie die Ordnerhierarchie unter dem zu archivierenden übergeordneten Verzeichnis bei:
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önnen Sie dies ändern, um es pathlib
für das Globbing von Dateien zu verwenden .
So viele Antworten hier, und ich hoffe, ich kann mit meiner eigenen Version einen Beitrag leisten, die (übrigens) auf der ursprünglichen Antwort basiert, aber mit einer grafischeren Perspektive, wobei auch der Kontext für jedes zipfile
Setup und jede Sortierung verwendet wirdos.walk()
, um eine zu haben geordnete Ausgabe.
Mit diesen Ordnern und diesen Dateien (unter anderem) wollte ich .zip
für jeden cap_
Ordner eine 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 angewendet habe, 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)
Grundsätzlich öffne os.walk(path)
ich für jede Iteration einen Kontext zum zipfile
Einrichten und iteriere anschließend die Iteration files
, bei der es sich um eine list
Datei aus dem root
Verzeichnis handelt, wobei der relative Pfad für jede Datei basierend auf dem aktuellen root
Verzeichnis gebildet wird und an das angehängt wirdzipfile
laufenden Kontext angehängt wird .
Und die Ausgabe wird folgendermaßen dargestellt:
$ python3 zip_cap_dirs.py
Compressing: ./cap_01
Compressing: ./cap_02
Compressing: ./cap_03
Um den Inhalt jedes .zip
Verzeichnisses anzuzeigen, können Sie den folgenden less
Befehl verwenden:
$ 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
Hier ist ein moderner Ansatz mit Pathlib und einem Kontextmanager. Fügt die Dateien direkt in die Zip-Datei und nicht in einen Unterordner ein.
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))
Ich habe eine Funktion vorbereitet, indem ich die Lösung von Mark Byers mit den Kommentaren von Reimund und Morten Zilmer (relativer Pfad und einschließlich leerer Verzeichnisse) konsolidiert habe. Als Best Practicewith
Wird bei der Dateikonstruktion von ZipFile verwendet.
Die Funktion bereitet auch einen Standardnamen für die ZIP-Datei mit dem Namen des komprimierten Verzeichnisses und der Erweiterung '.zip' vor. Daher funktioniert es nur mit einem Argument: dem zu komprimierenden Quellverzeichnis.
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))
Nachdem ich die Vorschläge gelesen hatte, kam ich auf eine sehr ähnliche Art und Weise, die mit 2.7.x funktioniert, ohne "lustige" Verzeichnisnamen (absolut ähnliche Namen) zu erstellen, und nur den angegebenen Ordner innerhalb der Zip-Datei erstellt.
Oder nur für den Fall, dass Ihre Zip-Datei einen Ordner mit dem Inhalt des ausgewählten Verzeichnisses enthalten muss.
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 zum Erstellen einer Zip-Datei.
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()
make_archive
vonshutil
(wenn Sie ein einzelnes Verzeichnis rekursiv komprimieren möchten).