2012-08-01 127 views
3

我一直试图使用zipfileshutil.make_archive模块递归创建一个目录的zip文件。两个模块都很好用 - 除了空目录不会被添加到存档中。包含其他空目录的空目录也会被无提示地跳过。如何使用Python创建文件路径的zip文件,包括空目录?

我可以使用7Zip创建相同路径的存档并保留空目录。因此我知道这在文件格式本身内是可能的。我只是不知道如何在Python中做到这一点。有任何想法吗?谢谢!

+0

该负责的代码是[这里](http://hg.python.org/cpython/file/8f1a8e80f330/Lib/shutil.py#l452)。 – icktoofay 2012-08-01 02:36:33

+0

尝试在目录中添加一个虚拟文件,然后从存档中删除该文件,以查看zipfile实际上是否支持空目录(某些zip实现虽然不支持该格式)。 – Thomas 2012-08-01 02:38:21

回答

9

有使用压缩文件一个例子:

import os, zipfile 
from os.path import join 
def zipfolder(foldername, filename, includeEmptyDIr=True): 
    empty_dirs = [] 
    zip = zipfile.ZipFile(filename, 'w', zipfile.ZIP_DEFLATED) 
    for root, dirs, files in os.walk(foldername): 
     empty_dirs.extend([dir for dir in dirs if os.listdir(join(root, dir)) == []]) 
     for name in files: 
      zip.write(join(root ,name)) 
     if includeEmptyDIr: 
      for dir in empty_dirs: 
       zif = zipfile.ZipInfo(join(root, dir) + "/") 
       zip.writestr(zif, "") 
     empty_dirs = [] 
    zip.close() 

if __name__ == "__main__": 
    zipfolder('test1/noname/', 'zip.zip') 
+2

您的代码将绝对路径保存在存档中。我稍微修改它以保存相对路径(因为它将在另一台机器上解压缩),并且它工作得很好!谢谢您的帮助! – jamieb 2012-08-01 04:12:00

+0

是的,我也这样做了,但那很简单。 必须将项目回迁到2.6,所以我必须替换shutil.make_archive()调用。 – 2012-10-03 11:57:20

+0

在Python 2.7.3下进行测试,它不压缩空的dirs,但它确实压缩了其他所有内容。此外,'empty_dirs.extend([如果os.listdir(join(root,dir))== []])在目录中是dir,则只需要为每个根启动,而不是每个启动dir in root(因为空的dirs将会进入) – James 2012-12-19 11:08:49

0

您需要register a new archive format才能这样做,因为默认的ZIP归档程序不支持该功能。看看the meat of the existing ZIP archiver。使用您当前未使用的变量dirpath创建目录的归档程序。我找了如何创建一个空的目录,发现this

zip.writestr(zipfile.ZipInfo('empty/'), '') 

有了这一点,你应该能够编写必要的代码,使其归档空目录。

0

这是从Adding folders to a zip file using python解除,但唯一的功能,我已经试过的作品。列出的答案在Python 2.7.3下不起作用(不复制空目录,效率低下)。被尝试和测试了以下:

#!/usr/bin/python 
import os 
import zipfile 

def zipdir(dirPath=None, zipFilePath=None, includeDirInZip=True): 

    if not zipFilePath: 
     zipFilePath = dirPath + ".zip" 
    if not os.path.isdir(dirPath): 
     raise OSError("dirPath argument must point to a directory. " 
     "'%s' does not." % dirPath) 
    parentDir, dirToZip = os.path.split(dirPath) 
    #Little nested function to prepare the proper archive path 
    def trimPath(path): 
     archivePath = path.replace(parentDir, "", 1) 
     if parentDir: 
      archivePath = archivePath.replace(os.path.sep, "", 1) 
     if not includeDirInZip: 
      archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1) 
     return os.path.normcase(archivePath) 

    outFile = zipfile.ZipFile(zipFilePath, "w", 
     compression=zipfile.ZIP_DEFLATED) 
    for (archiveDirPath, dirNames, fileNames) in os.walk(dirPath): 
     for fileName in fileNames: 
      filePath = os.path.join(archiveDirPath, fileName) 
      outFile.write(filePath, trimPath(filePath)) 
     #Make sure we get empty directories as well 
     if not fileNames and not dirNames: 
      zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/") 
      #some web sites suggest doing 
      #zipInfo.external_attr = 16 
      #or 
      #zipInfo.external_attr = 48 
      #Here to allow for inserting an empty directory. Still TBD/TODO. 
      outFile.writestr(zipInfo, "") 
    outFile.close() 
相关问题