如何使用Python创建文件路径的zip文件,包括空目录?

时间:2012-08-01 02:33:24

标签: python zip zipfile shutil

我一直在尝试使用zipfileshutil.make_archive模块递归创建目录的zip文件。两个模块都运行良好 - 除了空目录不会添加到存档。包含其他空目录的空目录也会被静默跳过。

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

4 个答案:

答案 0 :(得分:12)

有一个使用zipfile的例子:

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')

答案 1 :(得分:0)

您需要register a new archive format来执行此操作,因为默认的ZIP存档程序不支持此功能。看看the meat of the existing ZIP archiver。创建自己的归档程序,使用当前未使用的dirpath变量创建目录。我查找了如何创建一个空目录并找到了this

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

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

答案 2 :(得分: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()

答案 3 :(得分:0)

public function storeTrainingOne($id,$type)
    {
          $tweet = DB::table('tweets')->where('id',$id)->first();
          if($type=='netral')
          {
            $netral = Storage::get('public/netral.txt');
            Storage::put('public/netral.txt',$netral."\n".$tweet->tweet);
            Session::flash('message','<div class="alert alert-success">
                                    success, click <a href="'.URL('/training#netral').'">here</a>
                                </div>');
            return redirect()->back();
          }
          elseif($type=='positif')
          {
              $positif = Storage::get('public/positif.txt');
              Storage::put('public/positif.txt',$positif."\n".$tweet->tweet);
              Session::flash('message','<div class="alert alert-success">
                                    success, click<a href="'.URL('/training#positif').'">here</a>
                                </div>');
              return redirect()->back();
          }
          else
          {
              $negatif = Storage::get('public/negatif.txt');
              Storage::put('public/negatif.txt',$negatif."\n".$tweet->tweet);
              Session::flash('message','<div class="alert alert-success">
                                    success, click<a href="'.URL('/training#negatif').'">here</a>
                                </div>');
              return redirect()->back();
          }
    }