Не уверен, что это все еще актуально, но такое же поведение имеет место и для словарей. Посмотрите на этот пример.
a = {'par' : [1,21,3], 'sar' : [5,6,8]}
b = a
c = a.copy()
a['har'] = [1,2,3]
a
Out[14]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}
b
Out[15]: {'har': [1, 2, 3], 'par': [1, 21, 3], 'sar': [5, 6, 8]}
c
Out[16]: {'par': [1, 21, 3], 'sar': [5, 6, 8]}
Как указывали другие, вы должны использовать zipfile . Документация сообщает вам, какие функции доступны, но на самом деле не объясняет, как вы можете использовать их, чтобы застегнуть весь каталог. Я думаю, что проще всего объяснить с помощью некоторого примера кода:
#!/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/
Как создать 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
Здесь zipped архив будет называться
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 :
$ python -m zipapp myapp $ python myapp.pyz
Чтобы добавить содержимое 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()
with
вместо того, чтобы называть close()
самостоятельно в конце?
– ArtOfWarfare
12 January 2018 в 17:37
Попробуйте ниже. Я работал для меня.
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()
Я внес некоторые изменения в код , данный Марк Байерсом . Внизу функция также добавит пустые каталоги, если они у вас есть. Примеры должны сделать более понятным, какой путь добавлен в 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)
Выше - простая функция, которая должна работать для простых случаев. Вы можете найти более элегантный класс в моем Gist: https://gist.github.com/Eccenux/17526123107ca0ac28e6
Самый простой способ - использовать shutil.make_archive . Он поддерживает как форматы zip, так и tar.
import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
Если вам нужно сделать что-то более сложное, чем застегнуть весь каталог (например, пропустить определенные файлы), вам нужно будет вставить в модуль zipfile как предлагали другие.
shutil
является частью стандартной библиотеки python. Это должен быть главный ответ
– AlexG
28 April 2017 в 19:19
У меня есть другой пример кода, который может помочь, используя 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!')
Я подготовил функцию, объединив решение Марка Байера с комментариями Реймунда и Мортена Зильмера (относительный путь и включая пустые каталоги). В качестве наилучшей практики with
используется в построении файла ZipFile.
Функция также подготавливает имя файла zip по умолчанию с именем zipped directory и расширением «.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)))
Эта функция рекурсивно закроет дерево каталогов, сжимает файлы и записывает правильные относительные имена файлов в архиве. Записи архива совпадают с файлами, созданными с помощью 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)
Вот вариант ответа 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 )
Вероятно, вы хотите посмотреть модуль zipfile
; есть документация в http://docs.python.org/library/zipfile.html .
Вы также можете os.walk()
индексировать структуру каталогов.
Современный Python (3.6+) с использованием модуля pathlib
для краткой ООП-подобной обработки путей и pathlib.Path.rglob()
для рекурсивного глобирования. Насколько я могу судить, это эквивалентно ответу Джорджа В. Рейли: молнии с сжатием, самый верхний элемент - это каталог, содержит пустые директории, использует относительные пути.
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 + ).
Для добавления сжатия к результирующему zip-файлу проверьте эту ссылку .
Вам нужно изменить:
zip = zipfile.ZipFile('Python.zip', 'w')
на
zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
# 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))
Вот современный подход, используя 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))
Если вам нужна такая функциональность, как папка сжатия любого общего графического файлового менеджера, вы можете использовать следующий код, он использует модуль 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()
Хорошо, после прочтения предложений, я придумал очень похожий способ, который работает с 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" )
os.path.relpath(os.path.join(root, file), os.path.join(path, '..'))
. Это позволит вам заархивировать каталог из любого рабочего каталога без получения абсолютных путей в архиве. – Reimund 29 June 2013 в 15:35shutil
делает это очень просто в одной строке. Пожалуйста, проверьте ответ ниже. – droidlabour 30 May 2017 в 18:24