【问题标题】:Recursively append files to zip archive in python递归地将文件附加到python中的zip存档
【发布时间】:2013-04-09 00:45:17
【问题描述】:

在 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

我错过了什么吗?

【问题讨论】:

    标签: python recursion zip


    【解决方案1】:

    问题是您明确要求它展平所有路径:

    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 条目。由于您对所有条目都这样做,因此整个事情最终都变平了。

    【讨论】:

    • 好的,我知道了。有没有办法将test/目录的contents设置为root,而不是目录本身?
    • 我不确定我是否理解。 test的内容是0个或多个文件或目录,根必须是目录。你的意思是你想要test 而不是它的父级是根——也就是说,你想要相对于'test/' 的路径?那只是os.path.relpath(path, 'test')。或者,如果您只想删除第一个组件,您可以os.path.split 一直到components 的列表,然后是os.path.join(*components[1:])。 (如果您想要后者,并且需要更多解释,我可以将其编辑到答案中。)
    【解决方案2】:

    我想通了。正如 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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-07
      • 1970-01-01
      • 1970-01-01
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-10
      相关资源
      最近更新 更多