55

我想创建一个 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'

非常欢迎任何帮助。

相关问题:如何使用 python(2.5 版)压缩文件夹的内容?

4

13 回答 13

66

你也可以使用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 中。

于 2011-06-28T19:05:19.627 回答
53

好的,在我理解了你想要什么之后,它就像使用 的第二个参数一样简单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 之后,文件消失了,但空目录仍然存在。

于 2009-01-19T22:21:46.883 回答
16

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 实现。我可以想到一种解决方法(在 zip“文件夹”中存储一个虚拟文件名,在提取时应该忽略它),但不能跨实现移植。

于 2009-01-19T21:34:13.453 回答
11
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)

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

干杯。

于 2009-03-22T07:03:11.440 回答
4

下面是一些用于将整个目录压缩到 zipfile 的代码。

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

我从这个速度评论线程这个 python 邮件列表线程中得到了一些信息。

请注意,此功能旨在将文件放入没有父目录或只有一个父目录的 zip 存档中,因此它将修剪文件系统路径中的任何前导目录,而不是将它们包含在 zip 存档路径中。当您只想获取一个目录并将其制作成可以在不同位置提取的 zip 文件时,通常会出现这种情况。

关键字参数:

dirPath -- 要归档的目录的字符串路径。这是唯一需要的参数。它可以是绝对的或相对的,但只有一个或零个前导目录将包含在 zip 存档中。

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

includeDirInZip -- 布尔值,指示是否应将顶级目录包含在存档中或省略。(默认为真)

(请注意,StackOverflow 似乎无法使用三引号字符串漂亮地打印我的 python,所以我只是将我的文档字符串转换为此处的帖子文本)

#!/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")
于 2009-04-27T03:53:45.827 回答
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()
于 2009-10-09T17:04:44.070 回答
3

如果您查看使用 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/.

于 2013-08-18T04:41:39.503 回答
3

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

因此,如果您有以下文件层次结构:

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

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

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

如果你想在 python 代码中使用它并使用导入的 zipfile 模块,你可以通过以下方式调用它的 main 函数:

import zipfile
zipfile.main(['-c', 'result.zip', 'file1.md', 'folder'])
于 2019-09-28T12:47:35.117 回答
2

添加一些导入后,您的代码对我来说运行良好,您如何调用脚本,也许您可​​以告诉我们“..\packed\bin”目录的文件夹结构。

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

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

`

于 2009-01-19T17:47:34.503 回答
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 文件中的文件夹。只是想发布我实际运行的代码,而不是我基于代码的代码。

于 2009-01-19T22:26:04.097 回答
0

非常感谢您提供这个有用的功能!我发现它非常有用,因为我也在寻求帮助。但是,也许稍微改变一下它会很有用

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

将会

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

因为发现如果我想压缩位于 'C:\folder\path\notWanted\to\zip\Example' 的文件夹 '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'
于 2009-12-15T10:17:30.763 回答
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()
于 2014-09-17T19:32:24.997 回答
-3

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

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

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

于 2009-03-24T08:06:09.293 回答