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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 11:57:34  来源:igfitidea点击:

Compressing directory using shutil.make_archive() while preserving directory structure

pythondirectoryzipshutil

提问by G Warner

I'm trying to zip a directory called test_dicomsto a zip file named test_dicoms.zipusing 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.txtand after I zip and unzip foo.txt's path is /home/code/foo.txtas 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_archivewill 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 使用起来太混乱了。

Here it is http://www.seanbehan.com/how-to-use-python-shutil-make_archive-to-zip-up-a-directory-recursively-including-the-root-folder/

这是http://www.seanbehan.com/how-to-use-python-shutil-make_archive-to-zip-up-a-directory-recursively-including-the-root-folder/

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)