读取和写zip文件而无需使用Zipfile模块提取
#编程 #教程 #python #module

您的日常生活中多久使用一次zip文件?

如果您曾经使用zip文件,那么您会知道许多文件和目录都被压缩到一个具有 .zip 文件扩展的文件中。

因此,要读取该文件,我们需要从zip格式中提取它们。

在本教程中,我们将实施一些Pythonic方法,用于在ZIP文件上执行各种操作,而无需提取它们。

为此,我们将使用Python的zipfile模块来很好,轻松地处理该过程。

什么是zip文件?

如上所述,zip文件包含一个或多个已被压缩的文件或目录。

zip是支持 无损数据压缩的存档文件格式。

无损压缩意味着原始数据将从压缩数据中完美地重构而不会丢失任何信息。

如果您想知道什么是存档文件,那么它是由一个或多个文件及其元数据组成的计算机文件

这种格式最初是在1989年创建的,最初是在PKware,Inc。的PKZIP实用程序中实施的,作为Thom Henderson先前的ARC压缩格式的替代。然后,除了pkzip.Source

以外,ZIP格式得到了许多软件实用程序的支持

ZIP-64_Internal_Layout

插图显示如何将文件放在磁盘上。Source

zip文件的需求是什么?

zip文件对于那些使用计算机并处理大型数字信息的人至关重要,因为它允许他们

  • 通过压缩文件的大小而不会丢失任何信息

  • 来减少存储要求
  • 提高网络的传输速度

  • 将您的所有相关文件累积到一个档案中,以进行更好的管理

  • 通过加密文件来提供安全性

如何使用Python操纵ZIP文件?

python提供了多种操纵邮政编码的工具,包括一些低级Python库,例如lzmabz2zlibzlibtarfile,以及许多其他帮助使用特定压缩算法来压缩和解压缩文件的其他帮助。

除了这些python具有一个名为zipfile的高级模块,该模块可帮助我们读取,写作,创建,提取和列出zip文件的内容。

Python的Zipfile

zipfile模块确实提供了方便的类和功能,用于阅读,写作和提取zip文件。

,但确实有限制:

  • 数据解密过程很慢,因为它在纯python上运行。

  • 它无法处理加密zip文件的创建。

  • 当前不支持使用多磁带zip文件。

打开ZIP文件用于阅读和写作

zipfile具有一个类ZipFile,它允许我们以不同的模式打开zip文件,并且完全像Python的open()函数一起工作。

有四种类型的模式 -

  • r:在阅读模式下打开文件。默认

  • w:写作模式。

  • a:附加到现有文件。

  • x:创建和写一个新文件。

zipfile也是上下文管理器,因此支持with语句。Source

import zipfile

with zipfile.ZipFile("sample.zip", mode="r") as arch:
    arch.printdir()

.........
File Name                                             Modified             Size
document.txt                                   2022-07-04 18:13:36           52
data.txt                                       2022-07-04 18:17:30        37538
hello.md                                       2022-07-04 18:33:02         7064

在这里,我们可以看到已经列出了sample.zip文件夹中的所有文件。

ZipFile中,第一个参数我们提供的是文件的路径,是字符串

然后,我们提供的第二个参数模式。读取模式默认是您是否通过它无关紧要。

然后,我们在arch上调用了.printdir(),它以ZipFile的实例为 以用户友好的格式打印目录

  • 文件名

  • 修改

  • 大小

通过使用尝试&除了处理错误

我们将使用BadZipFile类如何处理zipfile,该类别提供了易于阅读的错误。

# Provided valid zip file
try:
    with zipfile.ZipFile("sample.zip") as arch:
        arch.printdir()
except zipfile.BadZipFile as error:
    print(error)

.........
File Name                                             Modified             Size
document.txt                                   2022-07-04 18:13:36           52
data.txt                                       2022-07-04 18:17:30        37538
hello.md                                       2022-07-04 18:33:02         7064


# Provided bad zip file
try:
    with zipfile.ZipFile("not_valid_zip.zip") as arch:
        arch.printdir()
except zipfile.BadZipFile as error:
    print(error)

.........
File is not a zip file

第一个代码块成功运行并打印了sample.zip文件的内容,因为我们提供的zip文件是有效的zip文件,而我们提供了不良的zip文件 <<<。 /p>

我们可以通过使用is_zipfile函数检查zip文件是否有效。

# Example 1
valid = zipfile.is_zipfile("bad_sample.zip")
print(valid)

.........
False

# Example 2
valid = zipfile.is_zipfile("sample.zip")
print(valid)

........
True

如果文件是有效的zip文件,则返回True,否则返回False

# Print content if a file is valid
if zipfile.is_zipfile("sample.zip"):
    with zipfile.ZipFile("sample.zip") as arch:
        arch.printdir()

else:
    print("This is not a valid ZIP format.")

.........
File Name                                             Modified             Size
document.txt                                   2022-07-04 18:13:36           52
data.txt                                       2022-07-04 18:17:30        37538
hello.md                                       2022-07-04 18:33:02         7064

if zipfile.is_zipfile("bad_sample.zip"):
    with zipfile.ZipFile("sample.zip") as arch:
        arch.printdir()

else:
    print("This is not a valid ZIP format file.")

.........
This is not a valid ZIP format file.

编写zip文件

打开邮政编码以供写作,使用写模式 w

如果您要编写的文件存在,则w将截断现有文件并写入您传递的新内容。

import zipfile

# Adding a file
with zipfile.ZipFile('geekpython.zip', 'w') as myzip:
    myzip.write('geek.txt')

    myzip.printdir()

........
File Name                                             Modified             Size
geek.txt                                       2022-07-05 14:52:01           85

geek.txt将添加到运行代码后创建的geekpython.zip

添加多个文件

import zipfile

# Adding multiple files
with zipfile.ZipFile('geekpython.zip', 'w') as myzip:
    myzip.write('geek.txt')
    myzip.write('program.py')

    myzip.printdir()

........
File Name                                             Modified             Size
geek.txt                                       2022-07-05 14:52:01           85
program.py                                     2022-07-05 14:52:01          136

注意:您要提供的文件作为参数 .write 应该存在

如果您尝试创建目录或传递不存在的文件,它将抛出FileNotFoundError

import zipfile

# Passing a non-existing directory
with zipfile.ZipFile('hello/geekpython.zip', 'w') as myzip:
    myzip.write('geek.txt')

.........
FileNotFoundError: [Errno 2] No such file or directory: 'hello/geekpython.zip'

import zipfile

# Passing a non-existing file
with zipfile.ZipFile('geekpython.zip', 'w') as myzip:
    myzip.write('hello.txt')

........
FileNotFoundError: [WinError 2] The system cannot find the file specified: 'hello.txt'

将文件附加到现有的zip存档

将文件附加到现有的zip档案中使用模式 a

import zipfile

# Appending files to the existing zip file
with zipfile.ZipFile('geekpython.zip', 'a') as myzip:
    myzip.write("index.html")
    myzip.write("program.py")

    myzip.printdir()

.........
File Name                                             Modified             Size
geek.txt                                       2022-07-05 14:52:00           85
index.html                                     2022-07-05 15:32:35          176
program.py                                     2022-07-05 14:52:01          136

阅读元数据

有一些方法可以帮助我们阅读邮政编码的元数据。

  • .getinfo(filename):它返回一个ZipInfo对象,该对象包含有关filename提供的成员文件的信息。

  • .infolist():返回一个包含档案中每个成员的zipinfo对象的列表。

  • .namelist():按名称返回存档成员列表。

还有一个我们已经使用的.printdir()的函数。

import zipfile

with zipfile.ZipFile("geekpython.zip", mode="r") as arch:
    myzip = arch.getinfo("geek.txt")


print(myzip.filename)
>>> geek.txt

print(myzip.date_time)
>>> (2022, 7, 5, 14, 52, 0)

print(myzip.file_size)
>>> 85

print(myzip.compress_size)
>>> 85

使用.infolist()在指定的档案中提取有关文件的信息

import zipfile
import datetime

date = datetime.datetime

with zipfile.ZipFile("geekpython.zip", "r") as info:
    for arch in info.infolist():
        print(f"The file name is: {arch.filename}")
        print(f"The file size is: {arch.file_size} bytes")
        print(f"The compressed size is: {arch.compress_size} bytes")
        print(f"Date of creation: {date(*arch.date_time)}")

        print("-" * 15)

.........
The file name is: geek.txt
The file size is: 85 bytes
The compressed size is: 85 bytes
Date of creation: 2022-07-05 14:52:00
---------------
The file name is: index.html
The file size is: 176 bytes
The compressed size is: 176 bytes
Date of creation: 2022-07-05 15:32:34
---------------
The file name is: program.py
The file size is: 136 bytes
The compressed size is: 136 bytes
Date of creation: 2022-07-05 14:52:00
---------------

让我们看看更多方法

import zipfile
with zipfile.ZipFile("sample.zip", "r") as info:
    for arch in info.infolist():
        if arch.create_system == 0:
            system = "Windows"
        elif arch.create_system == 3:
            system = "UNIX"
        else:
            system = "Unknown"

        print(f"ZIP version: {arch.create_version}")
        print(f"Create System: {system}")
        print(f"External Attributes: {arch.external_attr}")
        print(f"Internal Attributes: {arch.internal_attr}")
        print(f"Comments: {arch.comment}")

        print("-" * 15)

.........
ZIP version: 20
Create System: Windows
External Attributes: 32
Internal Attributes: 1
Comments: b''
---------------
ZIP version: 20
Create System: Windows
External Attributes: 32
Internal Attributes: 1
Comments: b''
---------------
ZIP version: 20
Create System: Windows
External Attributes: 32
Internal Attributes: 1
Comments: b''
---------------

.create_system返回了整数

  • 0 - 对于Windows

  • 3 - 对于unix

显示使用.namelist()的示例

import zipfile

with zipfile.ZipFile("geekpython.zip", "r") as files:
    for files_list in files.namelist():
        print(files_list)

.........
geek.txt
index.html
program.py

阅读和写作成员文件

成员文件称为zip档案中存在的文件。

要在不提取成员文件的内容的情况下读取内容的内容,然后我们使用.read()。它占据了存档中文件的名称,而pwd是用于加密文件的密码。

import zipfile

with zipfile.ZipFile("geekpython.zip", "r") as zif:
    for lines in zif.read("intro.txt").split(b"\r\n"):
        print(lines)

.........
b'Hey, Welcome to GeekPython!'
b''
b'Are you enjoying it?'
b''
b"Now it's time, see you later!"
b''

我们使用saparator /r/n添加了.split()将字节流打印到行中,并添加了b作为后缀,因为我们正在使用字节对象。

除了.read()外,我们可以使用.open(),它允许我们以灵活的方式读取,写入和添加一个新文件,因为就像open()函数一样,它实现了上下文管理器协议,因此支持with语句。



import zipfile

with zipfile.ZipFile("sample.zip", "r") as my_zip:
    with my_zip.open("document.txt", "r") as data:
        for text in data:
            print(text)

.........
b'Hey, I a document file inside the sample.zip folder.\r\n'
b'\r\n'
b'Are you enjoying it.'

我们可以将.open()与Write Mode w一起创建一个新的成员文件并向其写入内容,然后我们可以将其附加到现有的存档。

import zipfile

with zipfile.ZipFile("sample.zip", "a") as my_zip:
    with my_zip.open("file.txt", "w") as data_file:
        data_file.write(b"Hi, I am a new file.")

with zipfile.ZipFile("sample.zip", mode="r") as archive:
    archive.printdir()
    print("-" * 20)
    for line in archive.read("file.txt").split(b"\n"):
        print(line)

.........
File Name                                             Modified             Size
data.txt                                       2022-07-04 18:17:30        37538
hello.md                                       2022-07-04 18:33:02         7064
document.txt                                   2022-07-06 17:08:36           76
file.txt                                       1980-01-01 00:00:00           20
--------------------
b'Hi, I am a new file.'

提取拉链档案

有两种提取Zip Archive

的方法
  • .extractall()-这使我们能够在当前工作目录中提取所有存档的所有成员。我们还可以指定我们选择的目录的路径。
import zipfile

with zipfile.ZipFile("geekpython.zip", "r") as file:
    file.extractall("files")

所有成员文件将在您当前的工作目录中提取到名为files的文件夹中。您可以指定另一个目录。

  • .extract()-允许我们从存档到当前工作目录中提取成员。您必须牢记一件事,需要指定会员的全名,否则必须是ZipInfo对象。
import zipfile
with zipfile.ZipFile("geekpython.zip", "r") as file:
    file.extract("hello.txt")

hello.txt将从档案中提取到当前工作目录。您可以指定您选择的输出目录。您只需要将path="output_directory/"指定为extract()中的参数。

创建zip文件

创建zip文件只是编写现有文件。

# Creating archive using zipfile module

files = ["hello.txt", "geek.md", "python.txt"]

with zipfile.ZipFile("archive_created.zip", "w") as archive:
    for file in files:
        archive.write(file)

,或者您可以直接指定全名来添加文件。

import zipfile

with zipfile.ZipFile("another_archive.zip", "w") as archive:
    archive.write("hello.txt")
    archive.write("geek.md")
    archive.write("python.txt")

使用 shutil 创建zip文件

我们可以使用shutil制作邮政编码,并提供了一种简单的方法。

Shutil模块有助于在Python中执行高级文件操作。

import shutil

shutil.make_archive("archive", "zip", "files")

这里的archive文件名将是作为邮政编码创建的,zip扩展名,将添加到文件中名称,而files是一个文件夹,其数据将被存档

使用shutil
解开zip档案

import shutil

shutil.unpack_archive("archive.zip", "archive")

这里的archive.zip zip存档archive是提取后要给出的文件的名称

压缩zip文件

通常,当我们使用zipfile制作邮政编码时,我们得到的结果实际上是未压缩,因为默认情况下它使用ZIP_STORED压缩方法。

就像成员文件存储在存档的容器中一样。

所以,我们需要在ZipFile中传递一个参数compression

有3种压缩文件的常数:

  • zipfile.ZIP_DEFLATED-需要一个zlib模块,压缩方法是 deflate

  • zipfile.ZIP_BZIP2-需要一个bz2模块,压缩方法为 bzip2

  • zipfile.ZIP_LZMA-需要一个lzma模块,压缩方法为 lzma

import zipfile
with zipfile.ZipFile("compressed.zip", "w", compression=zipfile.ZIP_DEFLATED) as archive:
    archive.write("geek.md")
    archive.write("python.txt")
    archive.write("hello.txt")

import zipfile
with zipfile.ZipFile("bzip_compressed.zip", "w", compression=zipfile.ZIP_BZIP2) as archive:
    archive.write("geek.md")
    archive.write("python.txt")
    archive.write("hello.txt")

我们还可以添加压缩级别。我们可以在09之间给出一个值。

import zipfile

with zipfile.ZipFile("max_compressed.zip", "w", compression=zipfile.ZIP_DEFLATED, compresslevel=9) as archive:
    archive.write("geek.md")
    archive.write("python.txt")
    archive.write("hello.txt")

您是否知道zipfile可以从命令行

运行

从命令行接口运行Zipfile

这里有一些选项,使我们可以从命令行列出,创建和提取邮政编码。

-l--list:列在zipfile中。

python -m zipfile -l data.zip

.........
File Name                                             Modified             Size
Streamlit-Apps-master/                         2022-06-30 23:31:36            0
Streamlit-Apps-master/Covid-19.csv             2022-06-30 23:31:36         1924
Streamlit-Apps-master/Covid-Banner.png         2022-06-30 23:31:36       538140
Streamlit-Apps-master/Procfile                 2022-06-30 23:31:36           40
Streamlit-Apps-master/Readme.md                2022-06-30 23:31:36          901
Streamlit-Apps-master/WebAppPreview.png        2022-06-30 23:31:36       145818
Streamlit-Apps-master/app.py                   2022-06-30 23:31:36         3162
Streamlit-Apps-master/requirements.txt         2022-06-30 23:31:36           46
Streamlit-Apps-master/setup.sh                 2022-06-30 23:31:36          220

它的作用就像.printdir()


-c--create:从源文件创建Zipfile。

python -m zipfile --create shell.zip python.txt hello.txt

它将创建一个名为shell.zip的邮政编码,并添加上面指定的文件名。

创建一个zip文件来存档整个目录

python -m zipfile --create directory.zip source/

python -m zipfile -l directory.zip

.........
File Name                                             Modified             Size
source/                                        2022-07-07 17:22:42            0
source/archive/                                2022-07-07 10:58:06            0
source/archive/hello.txt                       2022-07-07 10:58:06           62
source/archive/index.html                      2022-07-07 10:58:06          176
source/archive/intro.txt                       2022-07-07 10:58:06           86
source/archive/program.py                      2022-07-07 10:58:06          136
source/geek.md                                 2022-07-07 15:50:28           45
source/hello.txt                               2022-07-07 12:21:22           61

-e--extract:将zipfile提取到目标目录中。

python -m zipfile --extract directory.zip extracted/

directory.zip将提取到extracted目录中。


-t--test:测试邮政编码是否有效。

python -m zipfile --test bad_sample.zip

.........
Traceback (most recent call last):
...
BadZipFile: File is not a zip file

结论

phe,这是一个长长的模块,本文仍然没有覆盖所有内容。

但是,可以从zipfile模块开始并操纵邮政编码而无需提取它们是足够的。

zip文件确实具有一些好处

我们当然学到了一些有用的操作,我们可以使用zipfile模块在邮政编码上执行这些操作,例如:

  • 阅读,编写和提取现有的邮政编码

  • 阅读元数据

  • 创建邮政编码

  • 操纵成员文件

  • 从命令行运行zipfile


如果您喜欢这个

,您可能会感兴趣的其他文章

python发电机以及它们的工作方式有什么特别之处?

How to convert bytes into a string in Python

Understanding the different uses of asterisk(*) in Python

Different ways to display web and local images in Jupyter Notebook

How to access list items within the dictionary in Python

What is the difference between sort() and sorted() in Python

How to use super() function in Python classes

What are context managers in Python


这就是目前的全部

保持编码