#1 楼
正如其他人指出的那样,您应该使用zipfile。该文档告诉您可用的功能,但并未真正说明如何使用它们来压缩整个目录。我认为用一些示例代码来解释是最容易的:/
评论
我会在写调用中添加第二个参数,传递os.path.relpath(os.path.join(root,file),os.path.join(path,'..'))。这样一来,您就可以从任何工作目录中压缩目录,而无需在存档中获取完整的绝对路径。
–雷蒙德
2013年6月29日14:35
当我尝试压缩文件夹并将输出的zip输出到同一文件夹时,发生了一个有趣的递归。 :-)
– Sibbs赌博
17 Mar 23 '17 at 4:22
shutil仅需一行就可以轻松实现。请检查下面的答案。
– droidlabour
17年5月30日在18:24
您可能会对ziph.write(os.path.join(path,file),arcname = file)感兴趣,这样归档文件中的文件名就不会相对于硬盘驱动器了
–克里斯托弗·布林(Christophe Blin)
17年6月14日在7:42
啊,我错过了.close()调用!
–information_interchange
18年1月22日在21:04
#2 楼
最简单的方法是使用shutil.make_archive
。它支持zip和tar格式。import shutil
shutil.make_archive(output_filename, 'zip', dir_name)
如果您需要做的事情比压缩整个目录还要复杂(例如跳过某些文件),那么需要像其他人建议的那样深入研究
zipfile
模块。评论
shutil是标准python库的一部分。这应该是最佳答案
– AlexG
17-4-28在19:19
这是这里最简洁的答案,并且还具有直接将所有子目录和文件添加到归档中的优势,而不是将所有内容都包含在顶级文件夹中(这在解压缩时会导致文件夹结构中的冗余级别)。
–aitch-hat
17年6月22日在8:05
@cmcginty您能否更具体一点说明它的哪些方面不是线程安全的?一个调用时运行多个线程会导致解释器崩溃吗?
–std''OrgnlDave
17年11月4日在22:49
请注意,在Python 3.4之前,shutil.make_archive不支持ZIP64,并且在创建大于2GB的ZIP文件时将失败。
– azdev
18年1月18日在23:42
@Teekin否。如果查看错误报告(bugs.python.org/issue30511),您会看到shutil.make_archive使用os.chdir()。从我阅读的有关os.chdir()的内容来看,它在全球范围内运作。
–山姆·马来耶
18年7月25日在0:36
#3 楼
要将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:无效文件:
– Nishad Up
17年8月23日在12:41
您不能使用with而不是最后自己调用close()吗?
–ArtOfWarfare
18年1月12日在16:37
#4 楼
如何在Python中创建目录结构的zip存档?
在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
之前。它需要一个root_dir参数,用于cwd:make_archive('zipfile_name', 'zip', root_dir='.')
从外壳使用Python
从外壳程序使用Python也可以使用
zipfile
模块:不会自动执行),并且sourcedir是目录的路径。压缩Python(或者只是不希望父目录):
如果您正在尝试用
zipname
和.zip
压缩python包,而您不希望父目录,是$ python -m zipfile -c zipname sourcedir
和
$ python -m zipfile -c zipname sourcedir/*
将运行该程序包。 (请注意,您不能将压缩包中的子包作为入口运行。)
压缩Python应用程序:
如果您使用python3.5 +,尤其是要压缩Python包,请使用zipapp:
$ python zipname
#5 楼
此功能将递归压缩目录树,压缩文件,并在存档中记录正确的相对文件名。存档条目与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)
#6 楼
使用shutil,它是python标准库集的一部分。使用shutil非常简单(请参见下面的代码):
第一个arg:生成的zip / tar文件的文件名,
第二个arg:zip / tar,
第3个arg:dir_name
代码:
import shutil
shutil.make_archive('/home/user/Desktop/Filename','zip','/home/username/Desktop/Directory')
#7 楼
要将压缩添加到结果zip文件,请查看此链接。您需要更改:
zip = zipfile.ZipFile('Python.zip', 'w')
到
zip = zipfile.ZipFile('Python.zip', 'w', zipfile.ZIP_DEFLATED)
#8 楼
现代Python(3.6+)使用pathlib
模块进行简洁的类似OOP的路径处理,并使用pathlib.Path.rglob()
模块进行递归遍历。据我所知,这相当于George V. Reilly的答案:压缩压缩,最上面的元素是目录,保留空目录,使用相对路径。 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+中修复)。评论
太棒了!简洁!现代!
–在这里
4月27日6:46
#9 楼
我对Mark Byers给出的代码进行了一些更改。如果您有空目录,下面的函数还会添加空目录。通过示例可以更清楚地了解添加到zip的路径是什么。上面是一个简单函数,应在简单情况下使用。您可以在我的Gist中找到更优雅的课程:https://gist.github.com/Eccenux/17526123107ca0ac28e6
评论
使用os.path可以大大简化路径处理。看我的答案。
–乔治·赖利(George V. Reilly)
13年6月13日在18:09
错误:zipHandle.write(os.path.join(root,“。”))没有考虑basePath。
–写信
2014年8月30日在9:16
是的,您可能是对的。稍后,我对此进行了一些补充;-) gist.github.com/Eccenux/17526123107ca0ac28e6
– Nux
2014年8月30日18:00
#10 楼
我有另一个使用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!')
#11 楼
为了将文件夹层次结构保留在要归档的父目录下,一种简洁的方法: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, ""))
如果需要,可以更改为使用
pathlib
进行文件遍历。 br />#12 楼
您可能想看看zipfile
模块;在http://docs.python.org/library/zipfile.html上有文档。您可能还希望
os.walk()
为目录结构建立索引。#13 楼
以下是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 )
#14 楼
试试下面的一个。它为我工作。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()
#15 楼
如果要使用任何通用图形文件管理器的compress文件夹之类的功能,则可以使用以下代码,它使用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()
#16 楼
为了提供更大的灵活性,例如通过名称选择目录/文件,请使用: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)
评论
这会压缩,但不会压缩。
– Alex
18/12/12在16:50
#17 楼
假设您要压缩当前目录中的所有文件夹(子目录)。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))
#18 楼
这里有这么多答案,我希望我可以贡献自己的版本,该版本基于原始答案(顺便说一句),但具有更多的图形化视角,还为每个zipfile
设置使用上下文并对os.walk()
进行排序,以便有一个有序的输出。拥有这些文件夹和它们的文件(以及其他文件夹),我想为每个
.zip
文件夹创建一个cap_
: br />这是我应用的内容,带有注释,可以使您更好地理解该过程。$ 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
基本上,对于
os.walk(path)
的每次迭代,我都会为zipfile
打开上下文进行设置,然后迭代遍历files
目录中的文件list
,遍历root
目录,根据当前root
目录形成每个文件的相对路径,并附加到正在运行的zipfile
上下文中。输出显示如下:
$ 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)
查看内容每个
.zip
目录中,都可以使用less
命令:$ python3 zip_cap_dirs.py
Compressing: ./cap_01
Compressing: ./cap_02
Compressing: ./cap_03
#19 楼
压缩文件或树(目录及其子目录)。from pathlib import Path
from zipfile import ZipFile, ZIP_DEFLATED
def make_zip(tree_path, zip_path, mode='w', skip_empty_dir=False):
with ZipFile(zip_path, mode=mode, compression=ZIP_DEFLATED) as zf:
paths = [Path(tree_path)]
while paths:
p = paths.pop()
if p.is_dir():
paths.extend(p.iterdir())
if skip_empty_dir:
continue
zf.write(p)
要附加到现有档案,请传递
mode='a'
,以创建新的档案mode='w'
(上述默认设置)。假设您要将3个不同的目录树捆绑在同一个归档文件中。make_zip(path_to_tree1, path_to_arch, mode='w')
make_zip(path_to_tree2, path_to_arch, mode='a')
make_zip(path_to_file3, path_to_arch, mode='a')
#20 楼
这是使用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))
#21 楼
我通过将Mark Byers的解决方案与Reimund和Morten Zilmer的注释(相对路径,包括空目录)合并在一起来准备函数。作为最佳实践,在ZipFile的文件构造中使用with
。 该函数还准备一个默认的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)))
#22 楼
# 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))
#23 楼
好了,阅读建议后,我想到了一种与2.7.x相似的方式,而不创建“有趣的”目录名称(类似绝对的名称),并且只会在zip内创建指定的文件夹。 br />或者以防万一,您需要在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" )
#24 楼
创建zip文件的功能。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()
评论
请举例说明,以便我纠正我的答案
–嘘
19年1月29日在8:45
但是,zipfile“当前无法创建加密文件”(来自docs.python.org/3.9/library/zipfile.html)
–乔治
5月14日14:05
#25 楼
对于任何其他研究此问题并尝试将其程序存储在相同目录的人,并且它们都具有非常深的树形结构,并且由于zip文件本身已压缩而以递归结束,请尝试以下操作。这是一个组合Mark的答案和一些额外的检查,以确保zipfile本身没有递归zip压缩,并且没有不必要的较深的文件夹结构。否Users / user / Desktop / code /.../ working_directory /.../ etc。一种文件结构。
评论
不要使用已接受答案中建议的解决方案,而要使用shutil中的make_archive(如果要递归压缩单个目录)。