36

我正在尝试在我的脚本中创建一个函数,它将给定源目录 ( src) 的内容压缩到一个 zip 文件 ( dst)。例如,zip('/path/to/dir', '/path/to/file.zip'), where/path/to/dir是一个目录,并且/path/to/file.zip还不存在。我不想压缩目录本身,这在我的情况下完全不同。我想压缩目录中的文件(和子目录)。这就是我正在尝试的:

def zip(src, dst):
    zf = zipfile.ZipFile("%s.zip" % (dst), "w")
    for dirname, subdirs, files in os.walk(src):
        zf.write(dirname)
        for filename in files:
            zf.write(os.path.join(dirname, filename))
    zf.close()

这将创建一个本质上是/. 例如,如果我 zipped /path/to/dir,解压缩 zip 会创建一个目录,其中包含“path”,该目录中包含“to”等。

有没有人有一个不会导致这个问题的功能?

我不能强调这一点,它需要压缩目录中的文件,而不是目录本身。

4

3 回答 3

57

zipfile.write()方法采用一个可选arcname参数,该参数指定 zipfile 中的文件名。

src您可以使用它在开头剥离路径。在这里,我os.path.abspath()用来确保两者src和返回的文件名os.walk()都有一个共同的前缀。

#!/usr/bin/env python2.7

import os
import zipfile

def zip(src, dst):
    zf = zipfile.ZipFile("%s.zip" % (dst), "w", zipfile.ZIP_DEFLATED)
    abs_src = os.path.abspath(src)
    for dirname, subdirs, files in os.walk(src):
        for filename in files:
            absname = os.path.abspath(os.path.join(dirname, filename))
            arcname = absname[len(abs_src) + 1:]
            print 'zipping %s as %s' % (os.path.join(dirname, filename),
                                        arcname)
            zf.write(absname, arcname)
    zf.close()

zip("src", "dst")

使用这样的目录结构:

src
└── a
    ├── b
    │   └── bar
    └── foo

脚本打印:

zipping src/a/foo as a/foo
zipping src/a/b/bar as a/b/bar

生成的 zip 文件的内容是:

Archive:  dst.zip
  Length     Date   Time    Name
 --------    ----   ----    ----
        0  01-28-13 11:36   a/foo
        0  01-28-13 11:36   a/b/bar
 --------                   -------
        0                   2 files
于 2013-01-28T18:50:17.437 回答
1

据我所知,你很接近。您可以使用dirnameandbasename来确保您获取了正确的路径名:

>>> os.path.dirname("/path/to/dst")
'/path/to'
>>> os.path.basename("/path/to/dst")
'dst'

然后使用chdir您可以确保您在父级中,因此路径是相对的。

def zip(src, dst):
    parent = os.path.dirname(dst)
    folder = os.path.basename(dst)

    os.chdir(parent):
    for dirname, subdirs, filenames in os.walk(folder):
        ...

这将创建:

dst/a.txt
dst/b
dst/b/c.txt
...etc...

如果不想包含名称“dst”,您可以这样做os.chdir(dst)然后os.walk('.').

希望有帮助。

于 2013-01-28T18:38:37.400 回答
1

使用arcname参数控制 zip 文件中的名称/路径。

例如,对于仅包含文件、不包含目录的 zip 文件:

zf.write(os.path.join(dirname, filename), arcname=filename)

或者在 zip 文件中创建一个新目录:

zf.write(os.path.join(dirname, filename), arcname=os.path.join("my_zip_dir", filename))
于 2013-01-28T18:46:27.197 回答