递归地将文件附加到python中的zip存档

时间:2013-04-09 00:45:17

标签: python recursion zip

在Windows上的Python 2.7.4中,如果我有一个目录结构:

test/foo/a.bak
test/foo/b.bak
test/foo/bar/c.bak
test/d.bak

我使用以下内容将它们添加到现有存档中,以便'd.bak'位于存档的根目录中:

import zipfile
import os.path
import fnmatch

def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename

if __name__=='__main__':
    z = zipfile.ZipFile("testarch.zip", "a", zipfile.ZIP_DEFLATED)

    for filename in find_files('test', '*.*'):
        print 'Found file:', filename
        z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED)

    z.close()

zip文件的目录是平的。如果其中存在子目录,则会创建foo/目录 (如果我排除test/foo/bar/c.bak,则不会创建目录。包含它,foo/已创建,但如果有意义则不是foo/bar/,但没有子目录或文件:

foo/
a.bak
b.bak
c.bak
d.bak

我错过了什么吗?

2 个答案:

答案 0 :(得分:2)

问题在于你明确要求它展平所有路径:

z.write(filename, os.path.basename(filename), zipfile.ZIP_DEFLATED)

如果您查看the docs,则默认arcname为:

  

filename相同,但没有驱动器号并删除了前导路径分隔符

但是你用os.path.basename(filename)覆盖了它。 (如果您不知道basename做了什么,它将返回“最后一个路径名组件”。如果您不想只使用最后一个路径名组件,请不要调用basename。)

如果你只是z.write('test/foo/bar/c.bak'),它会创建一个名为test/foo/bar/c.bak的zip条目,但如果你z.write('test/foo/bar/c.bak', 'c.bak'),它将创建一个名为c.bak的zip条目。因为你为所有条目都这样做,所以整个事情最终变平了。

答案 1 :(得分:0)

我明白了。正如 abarnet 指出的那样,我误读了zipfiles上的文档。使用以下函数,我可以为zip文件创建正确的存档名称:

def createArchName(path):
    line = path
    if "\\" in line:
        ''' windows '''
        discard, val = line.split("\\", 1)
        return val
    else:
        ''' unix '''
        discard, val = line.split("/", 1)
        return val

对于有兴趣的人,完整的代码如下:

import urllib2
import zipfile
import os.path
import fnmatch

def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename

def createArchName(path):
    line = path
    if "\\" in line:
        ''' windows '''
        discard, val = line.split("\\", 1)
        return val
    else:
        ''' unix '''
        discard, val = line.split("/", 1)
        return val


if __name__=='__main__':
    if not os.path.exists("test"):
        os.mkdir("test")

    z = zipfile.ZipFile("testarch.zip", "a", zipfile.ZIP_DEFLATED)

    for filename in find_files('test', '*.*'):
        archname = createArchName(filename)
        print 'Found file:', archname
        z.write(filename, archname, zipfile.ZIP_DEFLATED)

    z.close()