精通Python自动化脚本-运维人员宝典完整目录:
第一章 Python脚本概述
第二章 Python脚本调试和性能测试
第三章 单元测试-单元测试框架的介绍
第四章 自动化常规运维活动
第五章 文件、目录和数据处理
第六章 文件存档、加密和解密
第七章 文本处理和正则表达式
第八章 文档和报告
第九章 操作各类文件
第十章 网络基础 – Socket编程
第十一章 使用Python脚本处理邮件
第十二章 使用Telnet和SSH远程监控主机
第十三章 创建图形化用户界面
第十四章 处理Apache和其它的日志文件
第十五章 SOAP和REST API通讯
第十六章 网络抓取 – 从网站上提取有用的信息
第十七章 数据收集及报表
第十八章 MySQL和SQLite数据库管理
前一章中我们学习了如何处理文件、目录和数据。我们还学习了tarfile模块。本章中,我们将学习文件的存档、加密和解密。存档在管理文件、目录和数据中扮演重要的角色。但首先什么是存档呢?存档是一个将多个文件和目录存放到一个文件中的过程。Python中有tarfile模块可用于创建这类存档文件。
本章中,我们将学习如下课题:
- 创建和解压存档包
- Tar包
- ZIP的创建
- 文件加密和解密
创建和解压存档包
这一部分中,我们将学习如何使用Python中的shutil模块来创建和解压存档包。shutil模块带有make_archive()函数,可以创建一个新的存档文件。使用make_archive(),我们可以对包含的内容的整个目录进行打包。
创建存档包
下面我们来编写一个名为shutil_make_archive.py的脚本并加入如下内容:
1 2 3 4 5 6 7 8 9 10 11 |
import tarfile, shutil, sys shutil.make_archive( 'work_sample', 'gztar', root_dir='..', base_dir='work' ) print('Archive contents:') with tarfile.open('work_sample.tar.gz', 'r') as t_file: for names in t_file.getnames(): print(names) |
运行程序,将得到如下输出:
1 2 3 4 |
$ python3 shutil_make_archive.py Archive contents: work work/sample.txt |
上例中,我们使用了Python中的shutil和tarfile模块来创建存档文件。在shutil.make_archive()中,我们指定了work_sample来作为存档文件的名称并使用 gz 格式。我们还通过基本目录属性指定了工作目录。最后,我们打印出了存档中的文件名称。
解压存档包
要解压存档包,可使用shutil中带有的unpack_archive()函数。使用该函数,我们可以提取存档的文件。我们传递存档包名以及想要提取内容的目录名。如果未传递目录名,就会将提取的内容放到当前工作目录中。
下面创建一个名为shutil_unpack_archive.py的脚本并编写如下代码:
1 2 3 4 5 6 7 8 |
import pathlib, shutil, sys, tempfile with tempfile.TemporaryDirectory() as d: shutil.unpack_archive('work_sample.tar.gz', extract_dir='/home/student/work') prefix_len = len(d) + 1 for extracted in pathlib.Path(d).rglob('*'): print(str(extracted)[prefix_len:]) |
运行脚本如下:
1 |
$ python3 shutil_unpack_archive.py |
下面检查work/目录,会在其中发现work/文件夹,并包含提取的文件。
Tar包
这一部分我们将学习tarfile模块。我们还将学习输入文件名的测试,评估它是否是有效的存档文件名。我们会看如何将一个新文件加入到已有的存档文件中,如何使用tarfile模块读取元数据,以及如何使用extractall() 函数来从存档中提取文件。
首先,我们将测试输入的文件名是否是有效的存档文件。进行这一测试,tarfile模块带有is_tarfile()函数,返回的是布尔值。
创建一个名为check_archive_file.py的脚本并编写如下内容:
1 2 3 4 5 6 7 |
import tarfile for f_name in ['hello.py', 'work.tar.gz', 'welcome.py', 'nofile.tar', 'sample.tar.xz']: try: print('{:} {}'.format(f_name, tarfile.is_tarfile(f_name))) except IOError as err: print('{:} {}'.format(f_name, err)) |
运行脚本,将得到如下输出:
1 2 3 4 5 6 |
$ python3 check_archive_file.py hello.py False work.tar.gz True welcome.py False nofile.tar [Errno 2] No such file or directory: 'nofile.tar' sample.tar.xz False |
因此,tarfile.is_tarfile()会检查列表出的各个文件名。hello.py, welcome.py文件不是tar包,所以得到的是布尔值False,work.tar.gz和sample.tar.xz是tar包,因此得到了布尔值True。并且目录中不存在nofile.tar这一文件,所以抛出了脚本中所编写的异常。
下面我们将向已创建的存档文件中添加一个新文件。创建名为add_to_archive.py的脚本并编写如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
import shutil, os, tarfile print('creating archive') shutil.make_archive('work', 'tar', root_dir='..', base_dir='work',) print('\nArchive contents:') with tarfile.open('work.tar', 'r') as t_file: for names in t_file.getnames(): print(names) os.system('touch sample.txt') print('adding sample.txt') with tarfile.open('work.tar', mode='a') as t: t.add('sample.txt') print('contents:',) with tarfile.open('work.tar', mode='r') as t: print([m.name for m in t.getmembers()]) |
运行脚本,我们将得到如下输出:
1 2 3 4 5 6 7 8 9 10 11 12 |
$ python3 add_to_archive.py # 输出结果: creating archive Archive contents: work work/work work/work/sample.txt adding sample.txt contents: ['work', 'work/work', 'work/work/sample.txt', 'sample.txt'] |
本例中,首先我们使用shutil.make_archive()创建了一个压缩文件,然后我们打印出了存档文件中的内容。再后我们在下一条语句中创建了一个sample.txt文件。接着我们希望将sample.txt加到已创建的work.tar中。这里我们使用了追加模式。接下来我们再次读取了存档文件中的内容。
下面我们将学习如何读取存档文件的元数据。getmembers() 会加载文件的元数据。创建一个名为read_metadata.py的脚本并编写如下内容:
1 2 3 4 5 6 7 8 |
import tarfile, time with tarfile.open('work.tar', 'r') as t: for file_info in t.getmembers(): print(file_info.name) print('Size :', file_info.size, 'bytes') print('Type :', file_info.type) print() |
运行脚本,将会得到如下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
$ python3 read_metadata.py work Size : 0 bytes Type : b'5' work/work Size : 0 bytes Type : b'5' work/work/sample.txt Size : 0 bytes Type : b'0' sample.txt Size : 0 bytes Type : b'0' |
下面我们将使用 extractall() 函数来从存档包中提取内容。为此,创建一个名为extract_contents.py的脚本并在其中编写如下代码:
1 2 3 4 5 6 |
import tarfile, os os.mkdir('work') with tarfile.open('work.tar', 'r') as t: t.extractall('work') print(os.listdir('work')) |
运行脚本,将得到如下输出:
1 2 3 4 |
$ python3 extract_contents.py # 输出结果: ['sample.txt', 'work'] |
查看当前工作目录,我们会看到work/ 目录,进入该目录就可以看到提取的文件。
ZIP的创建
这部分中,我们将使用ZIP文件。我们将学习Python中的zipfile模块,如何创建ZIP文件,如何测试输入的文件名是否是有效的ZIP文件名,读取元数据等等。
首先我们将学习如何使用shutil模块的make_archive()函数创建zip文件。创建一个名为make_zip_file.py的脚本并编写如下代码:
1 2 |
import shutil shutil.make_archive('work', 'zip', 'work') |
运行脚本如下:
1 |
$ python3 make_zip_file.py |
此时查看当前工作目录,就会发现work.zip文件。
接下来我们将测试所输入的zip文件名是否有效。为此可使用zipfile模块中的is_zipfile()函数。
创建一个脚本check_zip_file.py并编写如下内容:
1 2 3 4 5 6 7 |
import zipfile for f_name in ['hello.py', 'work.zip', 'welcome.py', 'sample.txt', 'test.zip']: try: print('{:} {}'.format(f_name, zipfile.is_zipfile(f_name))) except IOError as err: print('{:} {}'.format(f_name, err)) |
运行脚本如下:
1 2 3 4 5 6 7 8 |
$ python3 check_zip_file.py # 输出结果: hello.py False work.zip True welcome.py False sample.txt False test.zip False |
在本例中,我们使用了for循环来检查列表中的文件名。is_zipfile()函数会逐一检查文件名并在结果中返回布尔值。
下面我们将来看如何使用Python中的zipfile模块来读取存档的ZIP文件的元数据。创建一个名为read_zip_metadata.py的脚本,并编写如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import zipfile def meta_info(names): with zipfile.ZipFile(names) as zf: for info in zf.infolist(): print(info.filename) if info.create_system == 0: system = 'Windows' elif info.create_system == 3: system = 'Unix' else: system = 'UNKNOWN' print('System :', system) print('Zip Version :', info.create_version) print('Compressed :', info.compress_size, 'bytes') print('Uncompressed:', info.file_size, 'bytes') print() if __name__ == "__main__": meta_info('work.zip') |
执行脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
$ python3 read_zip_metadata.py make_zip_file.py System : Unix Zip Version : 20 Compressed : 49 bytes Uncompressed: 57 bytes sample.txt System : Unix Zip Version : 20 Compressed : 2 bytes Uncompressed: 0 bytes add_to_archive.py System : Unix Zip Version : 20 Compressed : 240 bytes Uncompressed: 483 bytes shutil_unpack_archive.py System : Unix Zip Version : 20 Compressed : 196 bytes Uncompressed: 269 bytes |
要获取zip文件的元数据信息,我们使用了ZipFile类的infolist()方法。
文件加密和解密
这一部分中我们将学习Python中的pyAesCrypt模块。pyAesCrypt是一个文件加密模块,使用AES256-CBC算法来对文件和二进制流文件加密和解密。
安装pyAesCrypt命令如下:
1 |
pip3 install pyAesCrypt |
创建名为file_encrypt.py的脚本并编写如下代码:
1 2 3 4 5 6 7 8 9 10 11 |
import pyAesCrypt from os import stat, remove # encryption/decryption buffer size - 64K bufferSize = 64 * 1024 password = '#Training' with open('sample.txt', 'rb') as fIn: with open('sample.txt.aes', 'wb') as fOut: pyAesCrypt.encryptStream(fIn, fOut, password, bufferSize) # get encrypted file size encFileSize = stat('sample.txt.aes').st_size |
运行脚本如下:
1 2 3 |
$ python3 file_encrypt.py # 无输入内容 |
请查看当前工作目录,我们会发现其中有一个sample.txt.aes文件。
本例中,我们首先的提及了缓冲大小和密码。然后涉及了需要加密的文件名。在encryptStream中,我们传入了加密的文件fIn,以及加密后的文件名fOut。我们将加密后的文件存储为sample.txt.aes。
下面我们将对sample.txt.aes文件进行解密来获取文件的内容。创建一个名为file_decrypt.py 的脚本并编写如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 |
import pyAesCrypt from os import stat, remove bufferSize = 64 * 1024 password = '#Training' encFileSize = stat('sample.txt.aes').st_size with open('sample.txt.aes', 'rb') as fIn: with open('sampleout.txt', 'wb') as fOut: try: pyAesCrypt.decryptStream(fIn, fOut, password, bufferSize, encFileSize) except ValueError: remove('sampleout.txt') |
运行脚本如下:
1 |
$ python3 file_decrypt.py |
现在查看当前工作目录。一个名为sampleout.txt的文件会被创建。这就是我们的解密后文件。
本例中,我们涉及到了解密的文件名sample.txt.aes。然后,我们解密后的文件为sampleout.txt。在decryptStream中,涉及到了要解密的文件fIn,以及解密后文件的名称fOut。
总结
本章中,我们学习了创建和提取存档文件。在管理文件、目录和数据时存档扮演着重要的角色。它还将许多文件和目录存入一个文件中。
我们深入学习了Python模块tarfile和zipfile,来让我们创建、提取和测试存档文件。我们可以将新文件添加到已有存档文件中、读取元数据、从存档中提取文件。我们还学习了使用pyAescrypt模块来进行文件加密和解密。
下一章中我们将学习Python 中的文本处理和正则表达式。Python有一称作正则表达式的非常强大的库,可以完成搜索和提取数据等任务。
课后问题
- 我们是否可以用加密的方式压缩数据?如果可以,如何进行?
- Python中的上下文管理器是什么?
- 什么是pickling和unpickling?
- Python中不函数类型有哪些?