在Python1024的基础篇中,我们已经介绍过文件管理和文本文件的读写:
语雀内容

在路径处理方面,3.6版本后,建议采用pathlib,它采用面向对象封装接口,使用起来比os.path更人性化。
在学习后续章节前,有必要先介绍几个基本的概念,方便后续的理解。

1、常见文件格式

文本文件其实是一种特殊的二进制文件,它约定了以字符格式的读取方式,字符符合ASCII或UNICODE等编码标准。因为文本文件太通用、太特殊(字符形式)了,我们把它单独列出对待。

其他二进制文件则随应用的不同,有各式各样的读写规则。比如:

  • PDF(Portable Document Format)文件,定义了一种独立于应用程序、硬件、操作系统的方式呈现文档的文件格式。它内部包含了大量类型的子元素,通过索引的方式嵌入在不同的位置。只有符合其规范的软件,才能读取,甚至修改PDF文件。PDF文件格式标准由Adobe定义:参考官网
  • 微软2007版本之后的Office文件,比如docx、pptx、xlsx,属于OpenXML文件格式。它是由微软开发的基于XML和ZIP压缩技术的文件规范,并于2008年正式成为国际标准。可以用解压缩软件打开这类文件,就能看到其内部结构。目前除了微软Office软件,我们也可以通过金山WPS、OpenOffice等软件打开其文档。
  • 图像文件的格式非常多,根据压缩算法不同,会设计不同的文件格式,比如:JPEG、TIFF、RAW、BMP、GIF、PNG。归根到底,图像代表的是色彩数据,是整块的内容,而描述其数据结构的,是文件头部信息。
  • 音频文件,保存的是声音信号的数字化,和图像一样,文件不同主要源于压缩算法的不同。我们常见的音频文件格式如:MP3、WAV、AAC、FLAC等,声音信号被数字化后保存在数据块中,同时由文件头描述数据块。关键信息如采样率、比特率、声道数。采样率是时间相关的概念,即每秒收集多少次声音样本信息。
  • 视频文件,保存的是图像和音频的合集,即视频文件可以拆分为视频和音频,其中视频是图像的合集,每秒钟有多少张图像,就是它的FPS帧率,帧率决定了视频的流畅度。此外,每张图像的分辨率多大,决定了它的清晰度,比如我们常说的720P代表1280×720的分辨率,1080P就是1920×1080的分辨率,即代表用1920×1080个像素点来表达一张图片信息。所以,视频文件尤其大,根据压缩算法的不同,常见的文件格式如:MP4、MOV、FLV、WMV、WEBM等。

当然,除了上面这些文件格式外,我们还可以定义自己的格式,只要定义的格式,能被对应软件支持打开和写入即可。换句话说,如果你定义的文件格式,没人写出软件去支持,那就没办法应用。或者,你自己写了软件,但大部分人都不知道,或不想用,那它也就丧失了应用价值。在软件行业向互联网演进过程中,淘汰了大量的软件,才诞生出目前相对稳定的互联网基础设施。
Youtube上有人做了一个视频,呈现了90年代到2020年间最受欢迎浏览器的更替:原地址。引用一个B站的:
点击查看【bilibili】

2、文本文件也有分类

文本文件,本质上是用于存储字符的文件。
所有那些以字符保存的文件格式,其实都是文本文件,只不过文本内容还有额外特定含义。
常见的比如:CSV、HTML、XML、JSON、JS、CSS,还有各种语言的代码。

2.1 CSV文件

CSV文件常用于保存数据表格,比如:

  1. 姓名, 电话, 地址
  2. 张三, 18900000001, 上海
  3. 李四, 13800000002, 广州

这就是一个典型的CSV文件,我们可以用文本编辑器打开它,也可以用Excel等软件打开它。
如果用Excel软件打开它,Excel会把英文逗号作为分隔符号,提取单元格内容,我们看到的就是一张表格。

Python同样也支持这类文件的读写,通过csv模块:

  1. import pathlib
  2. import csv
  3. path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
  4. csv_path = path.joinpath('hello.csv')
  5. with open(csv_path ,'r') as f:
  6. f_csv = csv.reader(f)
  7. headers = next(f_csv)
  8. for row in f_csv:
  9. for h, v in zip(headers, row):
  10. print(f'{h.strip()}: {v.strip()}')

这样就能读出CSV文件中的数据:

  1. 姓名: 张三
  2. 电话: 18900000001
  3. 地址: 上海
  4. 姓名: 李四
  5. 电话: 13800000002
  6. 地址: 广州

2.2 XML文件

XML(eXtensible Markup Language)是为了结构化存储和传输数据而生,是一种标记语言。

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <mail>
  3. <to>World</to>
  4. <from>程一初</from>
  5. <title>Hello World</title>
  6. <body>Welcome to Python1024!</body>
  7. </mail>

我们可以自定义标记,一种定义就是一种数据格式。
在Python中,有三种处理数据的方式:

  • DOM(Document Object Model):文档对象模型,是W3C组织推荐的标准编程接口。它把XML文件映射到内存中,以“树”的数据结构来操作数据。
  • SAX(simple API for XML):事件驱动模型,虽然不是标准,但应用广泛。它逐行扫描文档,边扫边解析,这样就不用一下子全装载到内存了。
  • ElementTree:性能介乎于DOM和SAX之间,使用门槛低。

以ElementTree为例:

  1. import pathlib
  2. import xml.etree.ElementTree as ET
  3. path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
  4. xml_path = path.joinpath('hello.xml')
  5. tree = ET.parse(xml_path)
  6. root = tree.getroot() # 根节点
  7. print('root_tag:', root.tag) # 根标签:mail
  8. for elem in root:
  9. print(f'{elem.tag}: {elem.text}')

此外,HTML是XML的一个子集,即HTML是一种特殊的XML,它定义了一整套标签规范,比如文字、超链接、表单等,按照这套规范来呈现HTML的应用就是浏览器了。当然,浏览器除了支持HTML,还需要支持JS脚本、CSS样式文件等其他规范。

2.3 JSON文件

相比XML文件格式,JSON文件格式更精简。同样的信息可以用更少的字符表示:

  1. {
  2. "mail": {
  3. "to": "World",
  4. "from": "程一初",
  5. "title": "Hello World",
  6. "body": "Welcome to Python1024!"
  7. }
  8. }

少了对称标记以及<>符号,JSON需要占用更少标记数据,所以它更常被用于互联网应用的数据传输。
Python也内置了处理模块json:

  1. import pathlib
  2. import json
  3. path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
  4. json_path = path.joinpath('hello.json')
  5. with open(json_path, 'r') as f:
  6. data = json.loads(f.read())
  7. print(f'root_tag: {list(data.keys())[0]}')
  8. for k, v in data['mail'].items():
  9. print(f'{k}: {v}')

2.4 代码文件

代码文件,比如Python代码文件,也是一种文本文件。
所以,有一些静态代码检测工具,如pylint、pep8、flake8等,可以读取代码文件后检查编写质量。
甚至,你可以编写程序自动生成代码,在自动化测试中用的比较多。

代码文件的读取和其他文本文件一样,都可以用open()函数打开,但是要解析代码文件,就必须用“语法树”来解析,它也提供了对应的ast模块。
比如我们写一个简单的Python代码文件,包含一个注释块,以及一行代码:

  1. '''
  2. Author: 程一初
  3. '''
  4. print('hello world!')

然后用语法树解析它:

  1. import pathlib
  2. import ast
  3. path = list(pathlib.Path.cwd().parents)[1].joinpath('data/automate/001basic')
  4. py_path = path.joinpath('hello.py')
  5. with open(py_path, 'r') as f:
  6. node = ast.parse(f.read())
  7. # 获取文档注释
  8. print(ast.get_docstring(node))
  9. class MyVisitor(ast.NodeVisitor):
  10. # 定义一个遍历代码节点的类
  11. # 按需重定义generic_visit函数
  12. def generic_visit(self, node):
  13. print(node)
  14. super(MyVisitor, self).generic_visit(node)
  15. v = MyVisitor()
  16. v.visit(node)

会得到这样的结果:

  1. Author: 程一初
  2. <_ast.Module object at 0x118e4e890>
  3. <_ast.Expr object at 0x118ce1b50>
  4. <_ast.Str object at 0x118ce1f90>
  5. <_ast.Expr object at 0x118ce1d90>
  6. <_ast.Call object at 0x118ce1ad0>
  7. <_ast.Name object at 0x118ce1b10>
  8. <_ast.Load object at 0x103ed39d0>
  9. <_ast.Str object at 0x118eb3ed0>

第一行为注释文档,剩下8行为ast内部对象,包括模块、表达式、字符串、函数名、调用等。
这里只是举个例子,说明代码文件也是一种特殊的文本文件。
平时应用中,我们几乎不会这么去读写代码文件,而是直接用Python解释器来执行代码。

总结

了解什么是文件,就能明白每个文件都有自己的规范,想要处理某类文件,就得先找到符合规范的应用,或者模块。找到模块后,就可以通过结构化的代码来批量处理了。

常见的自动化处理无非就这几种:

  • 批量文件处理,比如某个文件夹下的所有文件统一重命名;
  • 根据提前设定的规则,自动分类处理文件,比如按文件后缀调用不同程序处理;
  • 组成流水线:把重复的工作提炼出标准,把每一步程序化后再组装起来。

Python的魅力,就是能把所有重复的工作,按模块组织起来,形成流水线,一个人发挥N个人的效率。

加入学习群

1、常见文件格式 - 图1