Не используйте решение, предложенное в принятом ответе, но одно из следующих, используя make_archivefrom shutil(если вы хотите рекурсивно сжать один каталог).
Малана
Ответы:
527
Как уже отмечали другие, вы должны использовать zipfile . Документация говорит вам, какие функции доступны, но не объясняет, как вы можете использовать их для архивирования всего каталога. Я думаю, что это проще всего объяснить с помощью некоторого примера кода:
#!/usr/bin/env pythonimport os
import zipfile
def zipdir(path, ziph):# ziph is zipfile handlefor 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()
Я бы добавил второй аргумент в вызов write, передавая os.path.relpath(os.path.join(root, file), os.path.join(path, '..')). Это позволило бы вам заархивировать каталог из любого рабочего каталога, не получая полных абсолютных путей в архиве.
Реймунд
8
Происходит забавная рекурсия, когда я пытаюсь заархивировать папку и вывести результирующий zip-файл в ту же папку. :-)
Sibbs Gambling
13
shutilделает это действительно просто в одну строку. Пожалуйста, проверьте ответ ниже ..
droidlabour
7
Вы можете быть более заинтересованы, выполнив ziph.write (os.path.join (путь, файл), arcname = file), чтобы имена файлов внутри архива не
Кристоф Блин
1
Ах, я пропустил .close()звонок!
информацией
1067
Самый простой способ - это использовать shutil.make_archive. Он поддерживает форматы zip и tar.
Если вам нужно сделать что-то более сложное, чем архивирование всего каталога (например, пропуск определенных файлов), то вам нужно будет покопаться в zipfileмодуле, как предлагали другие.
shutilявляется частью стандартной библиотеки Python. Это должен быть главный ответ
AlexG
4
Это самый краткий ответ здесь, а также имеет преимущество, заключающееся в добавлении всех подкаталогов и файлов в архив напрямую, а не в том, что все включено в папку верхнего уровня (что приводит к избыточному уровню в структуре папок при разархивировании).
aitch-hat
3
@cmcginty, не могли бы вы быть более конкретным относительно того, какой аспект не является поточно-ориентированным? Будет ли запуск нескольких потоков при вызове одного из них причиной сбоя интерпретатора?
std''OrgnlDave
13
Имейте в виду, что до Python 3.4 shutil.make_archive не поддерживает ZIP64 и не сможет создать файлы ZIP размером более 2 ГБ.
azdev
2
@ Текин Нет. Если вы посмотрите на отчет об ошибках (bugs.python.org/issue30511), вы увидите, что он shutil.make_archiveиспользует os.chdir(). Из того, о чем я читаю os.chdir(), это действует глобально.
Сэм Малаек
65
Чтобы добавить содержимое mydirectoryнового zip-файла, включая все файлы и подкаталоги:
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()
Для меня этот код выкидывает ниже ошибка TypeError: неверный файл: <zipfile.ZipFile [закрыто]>
Nishad Up
10
Разве вы не можете использовать withвместо того, чтобы называть close()себя в конце?
ArtOfWarfare
50
Как я могу создать zip-архив структуры каталогов в Python?
В скрипте Python
В Python 2.7+ shutilесть make_archiveфункция.
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
Здесь архив будет назван zipfile_name.zip. Если он base_dirнаходится ниже, root_dirон исключит файлы, не входящие в base_dir, но все же архивирует файлы в родительских каталогах доroot_dir .
У меня была проблема с тестированием на Cygwin с 2.7 - ему нужен аргумент root_dir для cwd:
make_archive('zipfile_name','zip', root_dir='.')
Использование Python из оболочки
Вы можете сделать это с помощью Python из оболочки, также используя zipfileмодуль:
$ python -m zipfile -c zipname sourcedir
Где zipnameимя нужного файла назначения (добавить.zip если хотите, он не будет делать это автоматически), а sourcedir - это путь к каталогу.
Архивирование Python (или просто не хочу родительский каталог):
Если вы пытаетесь сжать пакет python с помощью __init__.pyи __main__.py, и вам не нужен родительский каталог, это
$ python -m zipfile -c zipname sourcedir/*
А также
$ python zipname
будет запускать пакет. (Обратите внимание, что вы не можете запускать подпакеты в качестве точки входа из архива.)
Архивирование приложения Python:
Если у вас есть python3.5 + и вы хотите заархивировать пакет Python, используйте zipapp :
Эта функция рекурсивно сжимает дерево каталогов, сжимая файлы и записывая правильные относительные имена файлов в архиве. Архивные записи такие же, как и сгенерированные 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)
Я внес некоторые изменения в код, данный Марком Байерсом . Функция ниже также добавляет пустые каталоги, если они у вас есть. Примеры должны прояснить, какой путь добавляется в zip.
#!/usr/bin/env pythonimport 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 filesfor file in files:
filePath = os.path.join(root, file)
inZipPath = filePath.replace(basePath,"",1).lstrip("\\/")#print filePath + " , " + inZipPath
zipHandle.write(filePath, inZipPath)
Современный Python (3.6+) использует pathlibмодуль для краткой ООП-подобной обработки путей и pathlib.Path.rglob()для рекурсивного сглаживания. Насколько я могу судить, это эквивалентно ответу Джорджа В. Рейли: сжатие сжато, самый верхний элемент - это каталог, содержит пустые каталоги, использует относительные пути.
from pathlib importPathfrom zipfile import ZIP_DEFLATED,ZipFilefrom os importPathLikefrom typing importUniondef zip_dir(zip_name: str, source_dir:Union[str,PathLike]):
src_path =Path(source_dir).expanduser().resolve(strict=True)withZipFile(zip_name,'w', ZIP_DEFLATED)as zf:for file in src_path.rglob('*'):
zf.write(file, file.relative_to(src_path.parent))
Примечание: как указывают необязательные подсказки типа, zip_name не может быть объектом Path ( будет исправлено в 3.6.2+ ).
Если вам нужна такая функциональность, как папка сжатия любого обычного графического файлового менеджера, вы можете использовать следующий код, он использует модуль zipfile . Используя этот код, вы получите zip-файл с путем в качестве корневой папки.
import os
import zipfile
def zipdir(path, ziph):# Iterate all the directories and filesfor 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()
Например, вы можете выбрать только dir4и 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)
Или просто listdirв директории вызова скриптов и добавьте все оттуда:
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 thiscontinue
zipall(myzip, f)
Здесь так много ответов, и я надеюсь, что смогу внести свой вклад с моей собственной версией, которая основана на исходном ответе (кстати), но с более графической перспективой, также использующей контекст для каждой zipfileнастройки и сортировки os.walk(), чтобы иметь возможность упорядоченный вывод.
Имея эти папки и их файлы (среди прочих папок), я хотел создать .zipдля каждой cap_папки:
Вот то, что я применил, с комментариями для лучшего понимания процесса.
$ 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)
По сути, для каждой итерации os.walk(path)я открываю контекст для zipfileнастройки, а затем итерирую итерацию files, которая представляет собой listфайл из rootкаталога, формируя относительный путь для каждого файла на основе текущего rootкаталога, добавляя кzipfile контексту, который выполняется. ,
Вот современный подход, использующий pathlib и менеджер контекста. Помещает файлы прямо в zip, а не в подпапку.
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():ifnot 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))
Я подготовил функцию, объединив решение Марка Байерса с комментариями Реймунда и Мортена Цилмера (относительный путь и включая пустые каталоги). Как лучшая практика,with используется в конструкции файла ZipFile.
Функция также подготавливает имя файла zip по умолчанию с именем zip-каталога и расширением .zip. Следовательно, он работает только с одним аргументом: исходным каталогом, который нужно сжать.
# import required python modules# You have to install zipfile package using pip installimport 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 loopfor 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))
Что ж, после прочтения предложений я придумал очень похожий способ, который работает с 2.7.x без создания «забавных» имен каталогов (абсолютно похожих имен) и будет создавать только указанную папку внутри zip.
Или на тот случай, если вам нужно, чтобы ваш zip содержал папку внутри с содержимым выбранного каталога.
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")
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 directoryif 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
fromshutil
(если вы хотите рекурсивно сжать один каталог).Ответы:
Как уже отмечали другие, вы должны использовать zipfile . Документация говорит вам, какие функции доступны, но не объясняет, как вы можете использовать их для архивирования всего каталога. Я думаю, что это проще всего объяснить с помощью некоторого примера кода:
Адаптировано с: http://www.devshed.com/c/a/Python/Python-UnZipped/
источник
os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))
. Это позволило бы вам заархивировать каталог из любого рабочего каталога, не получая полных абсолютных путей в архиве.shutil
делает это действительно просто в одну строку. Пожалуйста, проверьте ответ ниже ...close()
звонок!Самый простой способ - это использовать
shutil.make_archive
. Он поддерживает форматы zip и tar.Если вам нужно сделать что-то более сложное, чем архивирование всего каталога (например, пропуск определенных файлов), то вам нужно будет покопаться в
zipfile
модуле, как предлагали другие.источник
shutil
является частью стандартной библиотеки Python. Это должен быть главный ответshutil.make_archive
используетos.chdir()
. Из того, о чем я читаюos.chdir()
, это действует глобально.Чтобы добавить содержимое
mydirectory
нового zip-файла, включая все файлы и подкаталоги:источник
with
вместо того, чтобы называтьclose()
себя в конце?В скрипте Python
В Python 2.7+
shutil
естьmake_archive
функция.Здесь архив будет назван
zipfile_name.zip
. Если онbase_dir
находится ниже,root_dir
он исключит файлы, не входящие вbase_dir
, но все же архивирует файлы в родительских каталогах доroot_dir
.У меня была проблема с тестированием на Cygwin с 2.7 - ему нужен аргумент root_dir для cwd:
Использование Python из оболочки
Вы можете сделать это с помощью Python из оболочки, также используя
zipfile
модуль:Где
zipname
имя нужного файла назначения (добавить.zip
если хотите, он не будет делать это автоматически), а sourcedir - это путь к каталогу.Архивирование Python (или просто не хочу родительский каталог):
Если вы пытаетесь сжать пакет python с помощью
__init__.py
и__main__.py
, и вам не нужен родительский каталог, этоА также
будет запускать пакет. (Обратите внимание, что вы не можете запускать подпакеты в качестве точки входа из архива.)
Архивирование приложения Python:
Если у вас есть python3.5 + и вы хотите заархивировать пакет Python, используйте zipapp :
источник
Эта функция рекурсивно сжимает дерево каталогов, сжимая файлы и записывая правильные относительные имена файлов в архиве. Архивные записи такие же, как и сгенерированные
zip -r output.zip source_dir
.источник
Используйте shutil, который является частью набора стандартных библиотек python. Использовать shutil очень просто (см. Код ниже):
Код:
источник
Чтобы добавить сжатие к полученному файлу почтового индекса, проверьте эту ссылку .
Вам нужно изменить:
в
источник
Я внес некоторые изменения в код, данный Марком Байерсом . Функция ниже также добавляет пустые каталоги, если они у вас есть. Примеры должны прояснить, какой путь добавляется в zip.
Выше простая функция, которая должна работать для простых случаев. Вы можете найти более элегантный класс в моем Gist: https://gist.github.com/Eccenux/17526123107ca0ac28e6
источник
Современный Python (3.6+) использует
pathlib
модуль для краткой ООП-подобной обработки путей иpathlib.Path.rglob()
для рекурсивного сглаживания. Насколько я могу судить, это эквивалентно ответу Джорджа В. Рейли: сжатие сжато, самый верхний элемент - это каталог, содержит пустые каталоги, использует относительные пути.Примечание: как указывают необязательные подсказки типа,
zip_name
не может быть объектом Path ( будет исправлено в 3.6.2+ ).источник
У меня есть другой пример кода, который может помочь, используя python3, pathlib и zipfile. Должно работать в любой ОС.
источник
Вы, вероятно, хотите посмотреть на
zipfile
модуль; есть документация по адресу http://docs.python.org/library/zipfile.html .Вы также
os.walk()
можете индексировать структуру каталогов.источник
Вот вариант ответа от Nux, который работает для меня:
источник
Попробуйте приведенный ниже. Он работал для меня .
источник
Если вам нужна такая функциональность, как папка сжатия любого обычного графического файлового менеджера, вы можете использовать следующий код, он использует модуль zipfile . Используя этот код, вы получите zip-файл с путем в качестве корневой папки.
источник
Для большей гибкости, например, выберите каталог / файл по имени, используйте:
Для файлового дерева:
Например, вы можете выбрать только
dir4
иroot.txt
:Или просто
listdir
в директории вызова скриптов и добавьте все оттуда:источник
Скажем, вы хотите сжать все папки (подкаталоги) в текущем каталоге.
источник
Для краткого способа сохранить иерархию папок в родительском каталоге для архивации:
Если вы хотите, вы можете изменить это, чтобы использовать
pathlib
для подстановки файлов .источник
Здесь так много ответов, и я надеюсь, что смогу внести свой вклад с моей собственной версией, которая основана на исходном ответе (кстати), но с более графической перспективой, также использующей контекст для каждой
zipfile
настройки и сортировкиos.walk()
, чтобы иметь возможность упорядоченный вывод.Имея эти папки и их файлы (среди прочих папок), я хотел создать
.zip
для каждойcap_
папки:Вот то, что я применил, с комментариями для лучшего понимания процесса.
По сути, для каждой итерации
os.walk(path)
я открываю контекст дляzipfile
настройки, а затем итерирую итерациюfiles
, которая представляет собойlist
файл изroot
каталога, формируя относительный путь для каждого файла на основе текущегоroot
каталога, добавляя кzipfile
контексту, который выполняется. ,И вывод представлен так:
Чтобы увидеть содержимое каждого
.zip
каталога, вы можете использоватьless
команду:источник
Вот современный подход, использующий pathlib и менеджер контекста. Помещает файлы прямо в zip, а не в подпапку.
источник
Я подготовил функцию, объединив решение Марка Байерса с комментариями Реймунда и Мортена Цилмера (относительный путь и включая пустые каталоги). Как лучшая практика,
with
используется в конструкции файла ZipFile.Функция также подготавливает имя файла zip по умолчанию с именем zip-каталога и расширением .zip. Следовательно, он работает только с одним аргументом: исходным каталогом, который нужно сжать.
источник
источник
Что ж, после прочтения предложений я придумал очень похожий способ, который работает с 2.7.x без создания «забавных» имен каталогов (абсолютно похожих имен) и будет создавать только указанную папку внутри zip.
Или на тот случай, если вам нужно, чтобы ваш zip содержал папку внутри с содержимым выбранного каталога.
источник
Функция для создания ZIP-файла.
источник
Используя zipfly
источник