2012-08-01 125 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() 
相關問題