使用python将文件夹添加到zip文件

时间:2009-01-19 17:33:18

标签: python file zip directory zipfile

我想创建一个zip文件。将文件夹添加到zip文件,然后将一堆文件添加到该文件夹​​。

所以我想最终得到一个带有文件的单个文件夹的zip文件。

我不知道在zip文件中使用文件夹或谷歌等文件夹的不良做法是否给了我任何关于这个主题的信息。

我从这开始:

def addFolderToZip(myZipFile,folder):
    folder = folder.encode('ascii') #convert path to ascii for ZipFile Method
    for file in glob.glob(folder+"/*"):
            if os.path.isfile(file):
                print file
                myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED)
            elif os.path.isdir(file):
                addFolderToZip(myZipFile,file)

def createZipFile(filename,files,folders):
    curTime=strftime("__%Y_%m_%d", time.localtime())
    filename=filename+curTime;
    print filename
    zipFilename=utils.getFileName("files", filename+".zip")
    myZipFile = zipfile.ZipFile( zipFilename, "w" ) # Open the zip file for writing 
    for file in files:
        file = file.encode('ascii') #convert path to ascii for ZipFile Method
        if os.path.isfile(file):
            (filepath, filename) = os.path.split(file)
            myZipFile.write( file, filename, zipfile.ZIP_DEFLATED )

    for folder in  folders:   
        addFolderToZip(myZipFile,folder)  
    myZipFile.close()
    return (1,zipFilename)


(success,filename)=createZipFile(planName,files,folders);

取自:http://mail.python.org/pipermail/python-list/2006-August/396166.html

删除所有文件夹并将目标文件夹(及其子文件夹)中的所有文件放入单个zip文件中。我无法让它添加整个文件夹。

如果我将路径提供给myZipFile.write中的文件夹,我会得到

  

IOError:[Errno 13]权限被拒绝:'.. \ packed \ bin'

非常欢迎任何帮助。

相关问题:How do I zip the contents of a folder using python (version 2.5)?

13 个答案:

答案 0 :(得分:51)

您也可以使用shutil

import shutil

zip_name = 'path\to\zip_file'
directory_name = 'path\to\directory'

# Create 'path\to\zip_file.zip'
shutil.make_archive(zip_name, 'zip', directory_name)

这会将整个文件夹放在zip中。

答案 1 :(得分:45)

好的,在我理解你想要的东西之后,它就像使用zipfile.write的第二个参数一样简单,你可以在那里使用你想要的任何东西:

import zipfile
myZipFile = zipfile.ZipFile("zip.zip", "w" )
myZipFile.write("test.py", "dir\\test.py", zipfile.ZIP_DEFLATED )

创建一个zipfile,其中test.py将被提取到名为dir

的目录中

编辑: 我曾经不得不在zip文件中创建一个空目录:这是可能的。 在上面的代码刚刚从zipfile中删除文件test.py之后,文件就消失了,但是空目录仍然存在。

答案 2 :(得分:14)

一个zip文件没有目录结构,只有一堆路径名及其内容。这些路径名应该相对于一个虚构的根文件夹(ZIP文件本身)。 “../”前缀在zip文件中没有明确的含义。

考虑您有一个文件a,并且您希望将其存储在zip文件中的“文件夹”中。在zipfile中存储文件时,您所要做的就是在文件名前添加文件夹名称:

zipi= zipfile.ZipInfo()
zipi.filename= "folder/a" # this is what you want
zipi.date_time= time.localtime(os.path.getmtime("a"))[:6]
zipi.compress_type= zipfile.ZIP_DEFLATED
filedata= open("a", "rb").read()

zipfile1.writestr(zipi, filedata) # zipfile1 is a zipfile.ZipFile instance

我不知道任何ZIP实现允许在ZIP文件中包含 empty 文件夹。我可以想到一个解决方法(在zip文件夹中存储一个虚拟文件名“,在提取时应该忽略它),但不能跨实现移植。

答案 3 :(得分:8)

import zipfile
import os


class ZipUtilities:

    def toZip(self, file, filename):
        zip_file = zipfile.ZipFile(filename, 'w')
        if os.path.isfile(file):
                    zip_file.write(file)
            else:
                    self.addFolderToZip(zip_file, file)
        zip_file.close()

    def addFolderToZip(self, zip_file, folder): 
        for file in os.listdir(folder):
            full_path = os.path.join(folder, file)
            if os.path.isfile(full_path):
                print 'File added: ' + str(full_path)
                zip_file.write(full_path)
            elif os.path.isdir(full_path):
                print 'Entering folder: ' + str(full_path)
                self.addFolderToZip(zip_file, full_path)

def main():
    utilities = ZipUtilities()
    filename = 'TEMP.zip'
    directory = 'TEMP'
    utilities.toZip(directory, filename)

main()

我正在跑步:

python tozip.py

这是日志:

havok@fireshield:~$ python tozip.py

File added: TEMP/NARF (7ª copia)
Entering folder: TEMP/TEMP2
File added: TEMP/TEMP2/NERF (otra copia)
File added: TEMP/TEMP2/NERF (copia)
File added: TEMP/TEMP2/NARF
File added: TEMP/TEMP2/NARF (copia)
File added: TEMP/TEMP2/NARF (otra copia)
Entering folder: TEMP/TEMP2/TEMP3
File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL
File added: TEMP/TEMP2/TEMP3/DOCUMENTO DEL FINAL (copia)
File added: TEMP/TEMP2/NERF
File added: TEMP/NARF (copia) (otra copia)
File added: TEMP/NARF (copia) (copia)
File added: TEMP/NARF (6ª copia)
File added: TEMP/NERF (copia) (otra copia)
File added: TEMP/NERF (4ª copia)
File added: TEMP/NERF (otra copia)
File added: TEMP/NERF (3ª copia)
File added: TEMP/NERF (6ª copia)
File added: TEMP/NERF (copia)
File added: TEMP/NERF (5ª copia)
File added: TEMP/NARF (8ª copia)
File added: TEMP/NARF (3ª copia)
File added: TEMP/NARF (5ª copia)
File added: TEMP/NERF (copia) (3ª copia)
File added: TEMP/NARF
File added: TEMP/NERF (copia) (copia)
File added: TEMP/NERF (8ª copia)
File added: TEMP/NERF (7ª copia)
File added: TEMP/NARF (copia)
File added: TEMP/NARF (otra copia)
File added: TEMP/NARF (4ª copia)
File added: TEMP/NERF
File added: TEMP/NARF (copia) (3ª copia)

正如您所看到的,它可以工作,存档也可以。这是一个递归函数,可以压缩整个文件夹。唯一的问题是它不会创建一个空文件夹。

干杯。

答案 4 :(得分:4)

以下是将整个目录压缩为zipfile的一些代码。

这似乎可以在Windows和Linux上创建zip文件。输出 文件似乎在Windows上正确提取(内置压缩文件夹功能, WinZip和7-Zip)和linux。但是,会出现zip文件中的空目录 成为一个棘手的问题。下面的解决方案似乎工作,但输出 Linux上的“zipinfo”令人担忧。此外,未设置目录权限 正确用于zip存档中的空目录。这似乎需要 更深入的研究。

我从this velocity reviews threadthis python mailing list thread获得了一些信息。

请注意,此功能旨在将文件放入zip存档中 要么没有父目录,要么只有一个父目录,所以它会修剪任何目录 文件系统路径中的前导目录,不包括在文件系统路径中 zip存档路径。当你想要一个时,通常就是这种情况 目录并将其转换为可以在不同中提取的zip文件 位置。

关键字参数:

dirPath - 要归档的目录的字符串路径。这是唯一的 必要的论点。它可以是绝对的或相对的,但只有一个或零 领先的目录将包含在zip档案中。

zipFilePath - 输出zip文件的字符串路径。这可能是绝对的 或相对路径。如果zip文件已存在,则会更新。如果 不会,它会被创建。如果要从头开始替换它,请将其删除 在调用此函数之前。 (默认值计算为dirPath +“.zip”)

includeDirInZip - 指示顶级目录是否应该的布尔值 包含在档案中或省略。 (默认为True)

(请注意,StackOverflow似乎无法完全打印我的python 三重引用的字符串,所以我只是将我的doc字符串转换为帖子文本)

#!/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()

以下是一些示例用法。请注意,如果您的dirPath参数有多个前导目录,则默认情况下仅包含最后一个目录。传递includeDirInZip = False以省略所有前导目录。

zipdir("foo") #Just give it a dir and get a .zip file
zipdir("foo", "foo2.zip") #Get a .zip file with a specific file name
zipdir("foo", "foo3nodir.zip", False) #Omit the top level directory
zipdir("../test1/foo", "foo4nopardirs.zip")

答案 5 :(得分:3)

这是我用来压缩文件夹的功能:

import os
import os.path
import zipfile

def zip_dir(dirpath, zippath):
    fzip = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED)
    basedir = os.path.dirname(dirpath) + '/' 
    for root, dirs, files in os.walk(dirpath):
        if os.path.basename(root)[0] == '.':
            continue #skip hidden directories        
        dirname = root.replace(basedir, '')
        for f in files:
            if f[-1] == '~' or (f[0] == '.' and f != '.htaccess'):
                #skip backup files and all hidden files except .htaccess
                continue
            fzip.write(root + '/' + f, dirname + '/' + f)
    fzip.close()

答案 6 :(得分:2)

添加一些导入后,你的代码运行正常,你如何调用脚本,也许你可以告诉我们'.. \ packed \ bin'目录的文件夹结构。

我使用以下参数调用了您的代码:

planName='test.zip'
files=['z.py',]
folders=['c:\\temp']
(success,filename)=createZipFile(planName,files,folders)

`

答案 7 :(得分:2)

如果查看使用Info-ZIP创建的zip文件,您会看到确实列出了目录:

$ zip foo.zip -r foo
  adding: foo/ (stored 0%)
  adding: foo/foo.jpg (deflated 84%)
$ less foo.zip
  Archive:  foo.zip
 Length   Method    Size  Cmpr    Date    Time   CRC-32   Name
--------  ------  ------- ---- ---------- ----- --------  ----
       0  Stored        0   0% 2013-08-18 14:32 00000000  foo/
  476320  Defl:N    77941  84% 2013-08-18 14:31 55a52268  foo/foo.jpg
--------          -------  ---                            -------
  476320            77941  84%                            2 files

请注意,目录条目的长度为零,未压缩。看来你可以通过按名称编写目录来实现与Python相同的功能,但强制它不使用压缩。

if os.path.isdir(name):
    zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_STORED)
else:
    zf.write(name, arcname=arcname, compress_type=zipfile.ZIP_DEFLATED)

可能值得确保arcname中的/结束。

答案 8 :(得分:0)

继承我编辑的编辑代码。它基于上面的代码,取自邮件列表。我添加了导入并制作了一个主程序。我还删掉了输出文件名,以缩短代码。

#!/usr/bin/env python

import os, zipfile, glob, sys

def addFolderToZip(myZipFile,folder):
    folder = folder.encode('ascii') #convert path to ascii for ZipFile Method
    for file in glob.glob(folder+"/*"):
            if os.path.isfile(file):
                print file
                myZipFile.write(file, os.path.basename(file), zipfile.ZIP_DEFLATED)
            elif os.path.isdir(file):
                addFolderToZip(myZipFile,file)

def createZipFile(filename,files,folders):
    myZipFile = zipfile.ZipFile( filename, "w" ) # Open the zip file for writing 
    for file in files:
        file = file.encode('ascii') #convert path to ascii for ZipFile Method
        if os.path.isfile(file):
            (filepath, filename) = os.path.split(file)
            myZipFile.write( file, filename, zipfile.ZIP_DEFLATED )

    for folder in  folders:   
        addFolderToZip(myZipFile,folder)  
    myZipFile.close()
    return (1,filename)

if __name__=="__main__":
    #put everything in sys.argv[1] in out.zip, skip files
    print createZipFile("out.zip", [], sys.argv[1])

在工作中,在我的Windows框中,此代码运行正常,但没有在zipfile中创建任何“文件夹”。至少我记得它确实如此。现在在家里,在我的Linux机器上,创建的zip文件似乎很糟糕:

$ unzip -l out.zip 
Archive:  out.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of out.zip or
        out.zip.zip, and cannot find out.zip.ZIP, period.

我不知道我是否意外地破坏了代码,我认为它是一样的。跨平台问题?无论哪种方式,它与我原来的问题无关;获取zip文件中的文件夹。只是想发布我实际运行的代码,而不是我基于代码的代码。

答案 9 :(得分:0)

非常感谢您对这个有用的功能!我发现它非常有用,因为我也在寻求帮助。但是,将它改变一点也许是有用的

basedir = os.path.dirname(dirpath) + '/'

将是

basedir = os.path.dirname(dirpath + '/')

因为发现如果我想把'C:\ folder \ path \ notWanted \'的文件夹'Example'压缩到'zip \ Example',

我进入了Windows:

dirpath = 'C:\folder\path\notWanted\to\zip\Example'
basedir = 'C:\folder\path\notWanted\to\zip\Example/'
dirname = 'C:\folder\path\notWanted\to\zip\Example\Example\Subfolder_etc'

但我想你的代码应该给出

dirpath = 'C:\folder\path\notWanted\to\zip\Example'
basedir = 'C:\folder\path\notWanted\to\zip\Example\'
dirname = '\Subfolder_etc'

答案 10 :(得分:0)

import os
import zipfile

zf = zipfile.ZipFile("file.zip", "w")
for file in os.listdir(os.curdir):
    if not file.endswith('.zip') and os.path.isfile(os.curdir+'/'+file):
        print file
        zf.write(file)
    elif os.path.isdir(os.curdir+'/'+file):
        print f
        for f in os.listdir(os.curdir+'/'+file):
            zf.write(file+'\\'+f)
zf.close()

答案 11 :(得分:0)

对我来说,最简单的方法是使用zipfile CLI(命令行界面)。 zipfile CLI可以将文件或文件夹作为参数,然后将其递归添加到存档中。

因此,如果您的文件层次结构为:

- file1.txt
- folder1 
   - file2.txt
   - file3.txt

您希望将所有内容都存档到“ result.zip”中,只需编写:

python -m zipfile -c result.zip file1.txt folder

如果要在python代码中使用它并使用导入的zipfile模块,可以通过以下方式调用其主要功能:

import zipfile
zipfile.main(['-c', 'result.zip', 'file1.md', 'folder'])

答案 12 :(得分:-2)

当您想要创建一个空文件夹时,您可以这样做:

    storage = api.Storage.open("empty_folder.zip","w")
    res = storage.open_resource("hannu//","w")
    storage.close()

文件夹没有在winextractor中显示,但是当你提取它时会显示它。