Python 使用shutil.make_archive() 压缩目录,同时保留目录结构
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32640053/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Compressing directory using shutil.make_archive() while preserving directory structure
提问by G Warner
I'm trying to zip a directory called test_dicoms
to a zip file named test_dicoms.zip
using the following code:
我正在尝试将名为的目录test_dicoms
压缩为test_dicoms.zip
使用以下代码命名的 zip 文件:
shutil.make_archive('/home/code/test_dicoms','zip','/home/code/test_dicoms')
shutil.make_archive('/home/code/test_dicoms','zip','/home/code/test_dicoms')
The problem is that when I unzip it, all of the files that were in /test_dicoms/
are extracted to /home/code/
instead of the folder /test_dicoms/
and all of it's contained files being extracted to /home/code/
. So /test_dicoms/
has a file called foo.txt
and after I zip and unzip foo.txt
's path is /home/code/foo.txt
as opposed to /home/code/test_dicoms/foo.txt
. How do I fix this? Also, some of the directories I'm working with are very large. Will I need to add anything to my code to make it ZIP64 or is the function smart enough to do that automatically?
问题是,当我解压缩它时,其中的所有文件都/test_dicoms/
被提取到/home/code/
而不是文件夹中,/test_dicoms/
并且所有包含的文件都被提取到/home/code/
. 所以/test_dicoms/
有一个名为的文件foo.txt
,在我 zip 和 unzip 之后foo.txt
的路径/home/code/foo.txt
与/home/code/test_dicoms/foo.txt
. 我该如何解决?此外,我正在使用的一些目录非常大。我是否需要在我的代码中添加任何内容以使其成为 ZIP64,或者该功能是否足够智能以自动执行此操作?
Here's what's currently in the archive created:
这是当前创建的存档中的内容:
[gwarner@jazz gwarner]$ unzip -l test_dicoms.zip
Archive: test_dicoms.zip
Length Date Time Name
--------- ---------- ----- ----
93324 09-17-2015 16:05 AAscout_b_000070
93332 09-17-2015 16:05 AAscout_b_000125
93332 09-17-2015 16:05 AAscout_b_000248
采纳答案by Rob?
Using the terms in the documentation, you have specified a root_dir, but not a base_dir. Try specifying the base_dirlike so:
使用文档中的术语,您指定了root_dir,但未指定base_dir。尝试像这样指定base_dir:
shutil.make_archive('/home/code/test_dicoms',
'zip',
'/home/code/',
'test_dicoms')
To answer your second question, it depends upon the version of Python you are using. Starting from Python 3.4, ZIP64 extensions will be availble by default. Prior to Python 3.4, make_archive
will not automatically create a file with ZIP64 extensions. If you are using an older version of Python and want ZIP64, you can invoke the underlying zipfile.ZipFile()
directly.
要回答您的第二个问题,这取决于您使用的 Python 版本。从 Python 3.4 开始,默认情况下将提供 ZIP64 扩展。在 Python 3.4 之前,make_archive
不会自动创建带有 ZIP64 扩展名的文件。如果您使用的是旧版本的 Python 并且想要 ZIP64,则可以zipfile.ZipFile()
直接调用底层。
If you choose to use zipfile.ZipFile()
directly, bypassing shutil.make_archive()
, here is an example:
如果选择zipfile.ZipFile()
直接使用,绕过shutil.make_archive()
,这里是一个例子:
import zipfile
import os
d = '/home/code/test_dicoms'
os.chdir(os.path.dirname(d))
with zipfile.ZipFile(d + '.zip',
"w",
zipfile.ZIP_DEFLATED,
allowZip64=True) as zf:
for root, _, filenames in os.walk(os.path.basename(d)):
for name in filenames:
name = os.path.join(root, name)
name = os.path.normpath(name)
zf.write(name, name)
Reference:
参考:
回答by seanbehan
I have written a wrapper function myself because shutil.make_archive is too confusing to use.
我自己写了一个包装函数,因为shutil.make_archive 使用起来太混乱了。
And just the code..
而只是代码..
import os, shutil
def make_archive(source, destination):
base = os.path.basename(destination)
name = base.split('.')[0]
format = base.split('.')[1]
archive_from = os.path.dirname(source)
archive_to = os.path.basename(source.strip(os.sep))
shutil.make_archive(name, format, archive_from, archive_to)
shutil.move('%s.%s'%(name,format), destination)
make_archive('/path/to/folder', '/path/to/folder.zip')
回答by Make42
I think, I am able to improve seanbehan's answer by removing the file moving:
我认为,我可以通过删除文件移动来改进 seanbehan 的回答:
def make_archive(source, destination):
base_name = '.'.join(destination.split('.')[:-1])
format = destination.split('.')[-1]
root_dir = os.path.dirname(source)
base_dir = os.path.basename(source.strip(os.sep))
shutil.make_archive(base_name, format, root_dir, base_dir)