使用shutil.make_archive()压缩目录,同时保留目录结构

时间:2015-09-17 21:11:42

标签: python directory zip shutil

我尝试使用以下代码将名为test_dicoms的目录压缩到名为test_dicoms.zip的zip文件中:

shutil.make_archive('/home/code/test_dicoms','zip','/home/code/test_dicoms')

问题在于,当我解压缩它时,/test_dicoms/中的所有文件都会被提取到/home/code/而不是文件夹/test_dicoms/,并且所有文件都包含在内正在提取到/home/code/的文件。因此,/test_dicoms/有一个名为foo.txt的文件,在我压缩和解压缩foo.txt之后,路径为/home/code/foo.txt而不是/home/code/test_dicoms/foo.txt。我该如何解决?此外,我正在使用的一些目录非常大。我是否需要在代码中添加任何东西以使其成为ZIP64,或者是否足够智能地自动执行此操作?

以下是创建档案中的内容:

[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

4 个答案:

答案 0 :(得分:29)

使用文档中的条款,您指定了 root_dir ,但未指定 base_dir 。尝试指定 base_dir ,如下所示:

shutil.make_archive('/home/code/test_dicoms',
                    'zip',
                    '/home/code/',
                    'test_dicoms')

要回答第二个问题,这取决于您使用的Python版本。从Python 3.4开始,默认情况下将提供ZIP64扩展。在Python 3.4之前,make_archive不会自动创建具有ZIP64扩展名的文件。如果您使用的是旧版本的Python并且想要使用ZIP64,则可以直接调用基础zipfile.ZipFile()

如果您选择直接使用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)

参考:

答案 1 :(得分:5)

我自己编写了一个包装函数,因为shutil.make_archive太难以使用了。

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

只是代码..

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')

答案 2 :(得分:1)

使用shutil基本上有两种方法:您可以尝试了解其背后的逻辑,也可以仅举一个示例。我在这里找不到示例,所以我尝试创建自己的示例。

; TLDR。从shutil.make_archive('dir1_arc', 'zip', root_dir='dir1')运行shutil.make_archive('dir1_arc', 'zip', base_dir='dir1')shutil.make_archive('dir1_arc', 'zip', 'dir1')或仅运行temp

假设您有~/temp/dir1

temp $ tree dir1
dir1
├── dir11
│   ├── file11
│   ├── file12
│   └── file13
├── dir1_arc.zip
├── file1
├── file2
└── file3

如何创建dir1的存档?设置base_name='dir1_arc'format='zip'。嗯,您有很多选择:

  • cd进入dir1并运行shutil.make_archive(base_name=base_name, format=format);它将在dir1_arc.zip内创建档案dir1;唯一的问题是您会遇到奇怪的行为:在存档中,您会找到文件dir1_arc.zip;
  • temp开始运行shutil.make_archive(base_name=base_name, format=format, base_dir='dir1');您将在dir1_arc.zip中看到temp,可以将其解压缩到dir1中; root_dir默认为temp;
  • ~开始运行shutil.make_archive(base_name=base_name, format=format, root_dir='temp', base_dir='dir1');您将再次获取文件,但是这次在~目录中;
  • temp2中创建另一个目录~并在其中运行:shutil.make_archive(base_name=base_name, format=format, root_dir='../temp', base_dir='dir1');您将在此temp2文件夹中找到归档文件;

是否可以在不指定参数的情况下运行shutil?您可以。从temp shutil.make_archive('dir1_arc', 'zip', 'dir1')开始运行。这与运行shutil.make_archive('dir1_arc', 'zip', root_dir='dir1')相同。在这种情况下,我们能对base_dir说些什么?从文档中得到的不多。从源代码中,我们可能会看到:

if root_dir is not None:
  os.chdir(root_dir)

if base_dir is None:
        base_dir = os.curdir 

因此,在我们的情况下,base_dirdir1。而且我们可以继续提出问题。

答案 3 :(得分:0)

我在某些带有“.”的路径上遇到路径拆分问题句号,我发现有一个默认为“zip”的可选格式很方便,并且仍然允许您覆盖其他格式并且不太容易出错。

for (int i = 1; i < N; i++) {
    for (int j = i; j < N; j += i) {
        ans[j].push_back(i);
    }
}
import os
import shutil
from shutil import make_archive

def make_archive(source, destination, format='zip'):
    import os
    import shutil
    from shutil import make_archive
    base, name = os.path.split(destination)
    archive_from = os.path.dirname(source)
    archive_to = os.path.basename(source.strip(os.sep))
    print(f'Source: {source}\nDestination: {destination}\nArchive From: {archive_from}\nArchive To: {archive_to}\n')
    shutil.make_archive(name, format, archive_from, archive_to)
    shutil.move('%s.%s' % (name, format), destination)

特别感谢 seanbehan 的原始回答,否则我会在酱汁中迷失更长时间。