跳至内容
Python

在 Python 中处理 Zip 文件

在本教程中,您将学习如何使用 zipfile 模块在 Python 中处理 Zip 文件。zipfile 是一个 Python 内置模块。
Hafeezul Kareem Shaik's photo
Hafeezul Kareem Shaik
已更新 · 13分钟 阅读

使用 AI 探索

ChatGPTClaudePerplexity

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。

处理 Zip 文件的先决条件

  • 您需要了解 Python 的文件处理,才能理解 Zip 文件的处理。如果您还不熟悉文件处理,请前往 W3Schools 的 File Handling 部分学习。
  • Python 的面向对象(OOP)概念
  • Python 基础概念,如条件语句、循环、函数、类等

打开这个 链接 以下载我在后续章节中使用的所有 Zip 文件夹。

什么是 Zip 文件?

Zip 是一种支持无损数据压缩的归档文件格式。Zip 文件是一个包含一个或多个压缩文件的单一文件。

Zip 文件的用途?

  • Zip 文件可以把所有相关文件放在一个地方。
  • Zip 文件有助于减小数据体积。
  • 在许多连接下,Zip 文件的传输速度比单个文件更快。

zipfile 模块

使用 dir() 方法探索 zipfile 模块的所有方法和类。查看下面的代码以获取该模块的所有类和方法。

import zipfile # importing the 'zipfile' module

print(dir(zipfile))
['BZIP2_VERSION', 'BadZipFile', 'BadZipfile', 'DEFAULT_VERSION', 'LZMACompressor', 'LZMADecompressor', 'LZMA_VERSION', 'LargeZipFile', 'MAX_EXTRACT_VERSION', 'PyZipFile', 'ZIP64_LIMIT', 'ZIP64_VERSION', 'ZIP_BZIP2', 'ZIP_DEFLATED', 'ZIP_FILECOUNT_LIMIT', 'ZIP_LZMA', 'ZIP_MAX_COMMENT', 'ZIP_STORED', 'ZipExtFile', 'ZipFile', 'ZipInfo', '_CD64_CREATE_VERSION', '_CD64_DIRECTORY_RECSIZE', '_CD64_DIRECTORY_SIZE', '_CD64_DISK_NUMBER', '_CD64_DISK_NUMBER_START', '_CD64_EXTRACT_VERSION', '_CD64_NUMBER_ENTRIES_THIS_DISK', '_CD64_NUMBER_ENTRIES_TOTAL', '_CD64_OFFSET_START_CENTDIR', '_CD64_SIGNATURE', '_CD_COMMENT_LENGTH', '_CD_COMPRESSED_SIZE', '_CD_COMPRESS_TYPE', '_CD_CRC', '_CD_CREATE_SYSTEM', '_CD_CREATE_VERSION', '_CD_DATE', '_CD_DISK_NUMBER_START', '_CD_EXTERNAL_FILE_ATTRIBUTES', '_CD_EXTRACT_SYSTEM', '_CD_EXTRACT_VERSION', '_CD_EXTRA_FIELD_LENGTH', '_CD_FILENAME_LENGTH', '_CD_FLAG_BITS', '_CD_INTERNAL_FILE_ATTRIBUTES', '_CD_LOCAL_HEADER_OFFSET', '_CD_SIGNATURE', '_CD_TIME', '_CD_UNCOMPRESSED_SIZE', '_ECD_COMMENT', '_ECD_COMMENT_SIZE', '_ECD_DISK_NUMBER', '_ECD_DISK_START', '_ECD_ENTRIES_THIS_DISK', '_ECD_ENTRIES_TOTAL', '_ECD_LOCATION', '_ECD_OFFSET', '_ECD_SIGNATURE', '_ECD_SIZE', '_EndRecData', '_EndRecData64', '_FH_COMPRESSED_SIZE', '_FH_COMPRESSION_METHOD', '_FH_CRC', '_FH_EXTRACT_SYSTEM', '_FH_EXTRACT_VERSION', '_FH_EXTRA_FIELD_LENGTH', '_FH_FILENAME_LENGTH', '_FH_GENERAL_PURPOSE_FLAG_BITS', '_FH_LAST_MOD_DATE', '_FH_LAST_MOD_TIME', '_FH_SIGNATURE', '_FH_UNCOMPRESSED_SIZE', '_SharedFile', '_Tellable', '_ZipDecrypter', '_ZipWriteFile', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', '_check_compression', '_check_zipfile', '_get_compressor', '_get_decompressor', 'binascii', 'bz2', 'compressor_names', 'crc32', 'error', 'importlib', 'io', 'is_zipfile', 'lzma', 'main', 'os', 're', 'shutil', 'sizeCentralDir', 'sizeEndCentDir', 'sizeEndCentDir64', 'sizeEndCentDir64Locator', 'sizeFileHeader', 'stat', 'stringCentralDir', 'stringEndArchive', 'stringEndArchive64', 'stringEndArchive64Locator', 'stringFileHeader', 'struct', 'structCentralDir', 'structEndArchive', 'structEndArchive64', 'structEndArchive64Locator', 'structFileHeader', 'sys', 'threading', 'time', 'zlib']

您看到了一堆类和方法,但并不需要全部掌握。本文只会介绍处理Zip 文件时常用的一些类和方法。

下面简要介绍一些有用的异常、类和方法。

异常

异常用于按需显示具体的错误信息。在 Python 中,您可以使用 try、except、finally 关键字进行错误处理。

如果您对错误处理不熟悉,请阅读 Python 官方文档的 Error Handling 章节。

来看一下 zipfile 模块中的所有异常。

zipfile.BadZipFile

zipfile.BadZipFile 是 zipfile 模块中的一个异常。当遇到损坏的 Zip 文件时会引发该错误。请看下面的示例。

## zipfile.BadZipFile
import zipfile

def main():
    try:
        with zipfile.ZipFile('sample_file.zip') as file: # opening the zip file using 'zipfile.ZipFile' class
            print("Ok")
    except zipfile.BadZipFile: # if the zip file has any errors then it prints the error message which you wrote under the 'except' block
        print('Error: Zip file is corrupted')

if __name__ == '__main__': main()

## I used a badfile for the test
Ok

zipfile.LargeZipFile

如果您要处理大型 Zip 文件,需要在打开 Zip 时启用 ZIP64 功能。否则会引发 LargeZipFile。如下示例所示。

## zipfile.LargeZipFile
## Without enabling 'Zip64'
import zipfile

def main():
    try:
        with zipfile.ZipFile('sample_file.zip') as file:
            print('File size is compatible')
    except zipfile.LargeZipFile: # it raises an 'LargeZipFile' error because you didn't enable the 'Zip64'
        print('Error: File size if too large')

if __name__ == '__main__': main()
File size is compatible
## zipfile.LargeZipFile
## With enabling 'ZIP64'
import zipfile

def main():
    try:
        with zipfile.ZipFile('sample_file.zip', mode = 'r', allowZip64 = True) as file: # here enabling the 'Zip64'
            print('File size is compatible')
    except zipfile.LargeZipFile:
        print('Error: File size if too large') # if the file size is too large to open it prints the error you have written

if __name__ == '__main__': main()
File size is compatible

请选择适合做异常处理演示的 Zip 文件并尝试运行程序,您会更清楚地理解。

类

简单来说,类是一组方法和属性的集合。您可以通过创建类的实例,在需要的地方调用这些方法和属性。

下面来看 zipfile 模块中的一些类。

zipfile.ZipFile

用于处理Zip 文件最常见的类是 ZipFile。

zipfile.ZipFile 用于读写 Zip 文件。它包含若干用于处理 Zip 文件的方法。

现在使用 dir() 来探索 ZipFile 类的方法。参见代码。

import zipfile

print(dir(zipfile.ZipFile)) # accessing the 'ZipFile' class
['_RealGetContents', '__class__', '__del__', '__delattr__', '__dict__', '__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_extract_member', '_fpclose', '_open_to_write', '_sanitize_windows_name', '_windows_illegal_name_trans_table', '_write_end_record', '_writecheck', 'close', 'comment', 'extract', 'extractall', 'fp', 'getinfo', 'infolist', 'namelist', 'open', 'printdir', 'read', 'setpassword', 'testzip', 'write', 'writestr']

您已经在前面的示例中使用过 zipfile.ZipFile 类来读取 Zip 文件。

zipfile.ZipFile 包含许多方法,如 extract、open、getinfo、setpassword 等,用于处理 Zip 文件。

我们来看一些 ZipFile 类的方法。

## zipfile.ZipFile
import zipfile

def main():
    with zipfile.ZipFile('sample_file.zip') as file:

        # ZipFile.infolist() returns a list containing all the members of an archive file
        print(file.infolist())

        # ZipFile.namelist() returns a list containing all the members with names of an archive file
        print(file.namelist())

        # ZipFile.getinfo(path = filepath) returns the information about a member of Zip file.
        # It raises a KeyError if it doesn't contain the mentioned file
        print(file.getinfo(file.namelist()[-1]))

        # ZipFile.open(path = filepath, mode = mode_type, pwd = password) opens the members of an archive file
        # 'pwd' is optional -> if it has password mention otherwise leave it
        text_file = file.open(name = file.namelist()[-1], mode = 'r')

        # 'read()' method of the file prints all the content of the file. You see this method in file handling.
        print(text_file.read())  

        # You must close the file if you don't open a file using 'with' keyword
        # 'close()' method is used to close the file
        text_file.close()

        # ZipFile.extractall(path = filepath, pwd = password) extracts all the files to current directory
        file.extractall()
        # after executing check the directory to see extracted files


if __name__ == '__main__': main()
[<ZipInfo filename='extra_file.txt' filemode='-rw-rw-rw-' file_size=59>, <ZipInfo filename='READ ME.txt' filemode='-rw-rw-rw-' file_size=59>, <ZipInfo filename='even_odd.py' filemode='-rw-rw-rw-' file_size=129>]
['extra_file.txt', 'READ ME.txt', 'even_odd.py']
<ZipInfo filename='even_odd.py' filemode='-rw-rw-rw-' file_size=129>
b"num = int(input('Enter a Number:- '))\r\nif num % 2 == 0:\r\n\tprint('{} is Even'.fromat(num))\r\nelse:\r\n\tprint('{} is Odd'.fromat(num))"

如果您想学习 ZipFile 类的全部方法,可以对想了解的方法使用 help() 函数。

或者访问 Python 官方的文档。

zipfile.ZipInfo

zipfile.ZipInfo 类用于表示 Zip 文件夹中的成员。

首先使用 dir() 方法探索 zipfile.ZipInfo 类的所有对象。见下方代码。

## zipfile.ZipInfo
import zipfile

print(dir(zipfile.ZipInfo))
['CRC', 'FileHeader', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', '_decodeExtra', '_encodeFilenameFlags', '_raw_time', 'comment', 'compress_size', 'compress_type', 'create_system', 'create_version', 'date_time', 'external_attr', 'extra', 'extract_version', 'file_size', 'filename', 'flag_bits', 'from_file', 'header_offset', 'internal_attr', 'is_dir', 'orig_filename', 'reserved', 'volume']

下面来看 zipfile.ZipInfo 类的一些方法。

## zipfile.ZipInfo
import zipfile

def main():
    with zipfile.ZipFile('sample_file.zip') as file:

        # 'infolist()' is the object of 'ZipFile' class
        # 'infolist()' returns a list containing all the folders and files of the zip -> 'ZipInfo' objects
        # assigning last element of the list to a variable to test all the methods of 'ZipInfo'
        archive = file.infolist()
        read_me_file = archive[-1]

        # 'ZipInfo' methods

        # ZipInfo_object.filename returns the name of the file
        print("Name of the file:- {}".format(read_me_file.filename))

        # ZipInfo_object.file_size returns the size of the file
        print("Size of the file:- {}".format(read_me_file.file_size))

        # ZipInfo_object.is_dir() returns True if it's directory otherwise False
        print("Is directory:- {}".format(read_me_file.is_dir()))

        # ZipInfo_object.date_time() returns the created date & time of file
        print("File created data & time:- {}".format(read_me_file.date_time))

if __name__ == '__main__': main()
Name of the file:- sample_file/READ ME.txt
Size of the file:- 59
Is directory:- False
File created data & time:- (2018, 10, 4, 11, 32, 22)

如果想进一步了解 ZipInfo 的对象,请访问 ZipInfo。

方法

方法是一段用于实现特定功能的代码块。例如,如果您想求一个数的绝对值,可以使用 Python 的内置方法 abs。

您可以在任何需要的地方使用这些方法。下面来看 zipfile 模块的一些方法。

zipfile.is_zipfile()

zipfile 模块的 is_zipfile(filename) 方法会在文件是有效 Zip 时返回 True,否则返回 False。

请看示例。

## zipfile.is_zip(filename)
import zipfile

def main():
    print(zipfile.is_zipfile('sample_file.zip')) # it returns True

if __name__ == '__main__': main()
True

处理 Zip 文件

本节将学习如何处理 Zip 文件,如打开、解压、写入等。

解压 Zip 文件

使用 extractall 方法将 Zip 文件中的文件解压到当前目录。

## extracting zip file
import zipfile

def main():

    # assigning filename to a variable
    file_name = 'sample_file.zip'

    # opening Zip using 'with' keyword in read mode
    with zipfile.ZipFile(file_name, 'r') as file:
        # printing all the information of archive file contents using 'printdir' method
        print(file.printdir())

        # extracting the files using 'extracall' method
        print('Extracting all files...')
        file.extractall()
        print('Done!') # check your directory of zip file to see the extracted files

if __name__ == '__main__': main()
File Name                                             Modified             Size
sample_file/                                   2018-10-04 11:33:22            0
sample_file/even_odd.py                        2018-06-29 23:35:54          129
sample_file/READ ME.txt                        2018-10-04 11:32:22           59
None
Extracting all files...
Done!

解压带密码的 Zip

要解压带密码的 Zip,需要为 extract(pwd = password) 或 extractall(pwd = password) 方法的 pwd 位置参数传入值。

密码必须以 bytes 形式传入。要将 str 转为 bytes,请使用 Python 的内置方法 bytes,并指定 utf-8 编码。

请看示例。

## extracting zip with password
import zipfile

def main():
    file_name = 'pswd_file.zip'
    pswd = 'datacamp'

    with zipfile.ZipFile(file_name) as file:
        # password you pass must be in the bytes you converted 'str' into 'bytes'
        file.extractall(pwd = bytes(pswd, 'utf-8'))

if __name__ == '__main__': main()

您也可以通过 ZipFile 类的 setpassword(pwd = password) 方法来设置密码再解压。见下例。

## extracting zip with password
import zipfile

def main():
    file_name = 'pswd_file.zip'
    pswd = 'datacamp'

    with zipfile.ZipFile(file_name) as file:
        # 'setpassword' method is used to give a password to the 'Zip'
        file.setpassword(pwd = bytes(pswd, 'utf-8'))
        file.extractall()

if __name__ == '__main__': main()

创建 Zip 文件

创建 Zip 文件无需额外方法。只需将名称传给 ZipFile 类,它就会在当前目录创建一个归档。

参见示例。

## Creating Zip file
import zipfile

def main():

    archive_name = 'example_file.zip'
    # below one line of code will create a 'Zip' in the current working directory
    with zipfile.ZipFile(archive_name, 'w') as file:
        print("{} is created.".format(archive_name))

if __name__ == '__main__': main()
example_file.zip is created.

向 Zip 文件写入

要向 Zip 写入文件,需要以写入模式打开归档文件。它会覆盖 Zip 中所有现有文件。

来看一个示例。

## Writing files to zip
import zipfile

def main():

    file_name = 'sample_file.zip'

    # Opening the 'Zip' in writing mode
    with zipfile.ZipFile(file_name, 'w') as file:
        # write mode overrides all the existing files in the 'Zip.'
        # you have to create the file which you have to write to the 'Zip.'
        file.write('extra_file.txt')
        print('File overrides the existing files')

    # opening the 'Zip' in reading mode to check
    with zipfile.ZipFile(file_name, 'r') as file:
        print(file.namelist())

if __name__ == '__main__': main()
File overrides the existing files
['extra_file.txt']

向 Zip 追加文件

要向 Zip 追加文件,需要以追加(a)模式打开 Zip。它不会覆盖现有文件。

请看示例。

## Appending files to zip
import zipfile

def main():

    file_name = 'sample_file.zip'

    # opening the 'Zip' in writing mode
    with zipfile.ZipFile(file_name, 'a') as file:
        # append mode adds files to the 'Zip'
        # you have to create the files which you have to add to the 'Zip'
        file.write('READ ME.txt')
        file.write('even_odd.py')
        print('Files added to the Zip')

    # opening the 'Zip' in reading mode to check
    with zipfile.ZipFile(file_name, 'r') as file:
        print(file.namelist())

if __name__ == '__main__': main()
Files added to the Zip
['extra_file.txt', 'READ ME.txt', 'even_odd.py']

到目前为止,您已经学习了如何处理 Zip 文件。现在您可以打开、写入、追加、解压、创建等。接下来,我们来编写一个小程序。

让我们看看要做什么?

使用循环和 zipfile 解压多个带密码的子 Zip

  • 您有一个 Zip 文件,内部嵌套了多个子 Zip 文件。每个 Zip 的密码都是它们各自的文件名。我们的任务是不断解压这些 Zip,直到抵达最深层。

解决步骤

  • 使用父级文件名作为密码解压父级文件。
  • 使用 namelist() 方法获取第一个子级的名称,并将其存入变量。
  • 运行一个无限循环。

    • 使用 is_zipfile() 方法检查该文件是否为 Zip。如果是,执行以下操作:

      • 使用 name 变量打开该 Zip。

      • 从 name 变量中获取该 Zip 的密码。

      • 解压该 Zip。

      • 获取下一个 Zip 的名称并存入 name 变量。

    • 否则

      • 使用 break 跳出循环。

以上是我设计的步骤。您也可以根据自己的文件结构进行调整。

## Solution
import zipfile

def main():

    # storing the parent name
    parent_file_name = '000.zip'

    with zipfile.ZipFile(parent_file_name, 'r') as parent_file:

        # extracting the parent file
        pswd = bytes(parent_file_name.split('.')[0], 'utf-8')
        parent_file.extractall(pwd = pswd)

        # getting the first child
        next_zip_name = parent_file.namelist()[0]

        # looping through the sub zips infinite times until you don't encouter a 'Zip' file
        while True:

            if zipfile.is_zipfile(next_zip_name):
                # opening the zip
                with zipfile.ZipFile(next_zip_name, 'r') as child_file:

                    # getting password from the zip name
                    pswd = bytes(next_zip_name.split('.')[0], 'utf-8')

                    # extracting the zip
                    child_file.extractall(pwd = pswd)

                    # getting the child zip name
                    next_zip_name = child_file.namelist()[0]
            else:
                break

if __name__ == '__main__': main()

运行上述程序后,您会看到所有子级 Zip 都被解压到当前目录。

结语

恭喜您完成本教程!

希望您喜欢这篇教程。本文在您处理 Zip 文件时会非常有用。现在,您已经能够处理 Zip 文件了。

如果您对文章有任何疑问,请在评论区留言。我会尽快回复。

再次提醒,如果您是 Python 初学者,可以学习 DataCamp 的免费课程 Intro to Python for Data Science,或阅读 Python 官方的文档。

祝您编码愉快!

主题
Python

Python 课程

课程

Python 入门

4 小时
7.1M
只需 4 小时就能掌握 Python 数据分析基础知识。 本在线课程将介绍 Python 接口并探索常用包。
查看详情开始课程

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。
查看更多