18 ответов:
Как уже упоминалось, вы должны использовать zipfile. Документация говорит вам, какие функции доступны, но на самом деле не объясняет, как вы можете использовать их для zip всего каталога. Я думаю, что это проще всего объяснить с помощью некоторого примера кода:
#!/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()адаптировано из: http://www.devshed.com/c/a/Python/Python-UnZipped/
самый простой способ-это использовать shutil.make_archive. Он поддерживает форматы zip и tar.
import shutil shutil.make_archive(output_filename, 'zip', dir_name)Если вам нужно сделать что-то более сложное, чем сжатие всего каталога (например, пропустить определенные файлы), то вам нужно будет копаться в модуле zipfile, как предлагали другие.
добавить содержимое
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()
как я могу создать zip-архив структуры каталогов в Python?
в скрипте Python
В Python 2.7+,
shutilесть
эта функция будет рекурсивно застегивать дерево каталогов, изменение размера файлы и записи правильных относительных имен файлов в архиве. Записи архива совпадают с записями, созданными
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-файл, проверьте этой ссылке.
вам нужно изменить:
zip = zipfile.ZipFile('Python.zip', 'w')до
zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
Я внес некоторые изменения в код, данный Марком Байерсом. Ниже функция также добавляет пустые папки, если они у вас есть. Примеры должны сделать более ясным, какой путь добавлен в zip.
#!/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)выше-это простая функция, которая должна работать для простых случаев. Вы можете найти более элегантный класс в моей сути: https://gist.github.com/Eccenux/17526123107ca0ac28e6
Вы, наверное, хотите посмотреть на
zipfileмодуль; есть документация по адресу http://docs.python.org/library/zipfile.html.вы также можете хотеть
os.walk()для индексации структуры каталогов.
У меня есть еще один пример кода, который может помочь, используя python3, pathlib и zipfile. Он должен работать в любой ОС.
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!')
вот вариант ответа, данного Nux, который работает для меня:
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 )
попробуйте ниже one. it работал для меня.
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()
современный Python (3.6+) с помощью
pathlibмодуль для краткой ООП-подобной обработки путей, иpathlib.Path.rglob()рекурсивный глоббинг. Насколько я могу судить, это эквивалентно ответу Джорджа В. Рейли: молнии со сжатием, самый верхний элемент-это каталог, сохраняет пустые dirs, использует относительные пути.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))Примечание: как дополнительные подсказки типа указывают,
zip_nameне может быть объектом Path (будет исправлено в 3.6.2+).
Если вам нужна такая функциональность, как папка сжатия любого общего графического файлового менеджера, вы можете использовать следующий код, он использует zipfile модуль. Используя этот код, вы получите zip-файл с путем в качестве корневой папки.
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()
вот современный подход, используя 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(): 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))
Я подготовил функцию, объединив решение Марка Байерса с комментариями Reimund и Morten Zilmer (относительный путь и включая пустые каталоги). Как лучшая практика,
withиспользуется в строительстве файл в zip-файл.функция также подготавливает имя zip-файла по умолчанию с именем заархивированного каталога и '.расширение zip'. Поэтому он работает только с одним аргументом: исходный каталог, который нужно сжать.
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))
Ну, после прочтения предложения я придумал очень похожий способ который работает с 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" )
чтобы обеспечить большую гибкость, например, выберите каталог / файл по имени используйте:
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для дерева файлов:
. ├── dir │ ├── dir2 │ │ └── file2.txt │ ├── dir3 │ │ └── file3.txt │ └── file.txt ├── dir4 │ ├── dir5 │ └── file4.txt ├── listdir.zip ├── main.py ├── root.txt └── selective.zipвы можете, например, выбрать только
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 this continue zipall(myzip, f)
Comments