配置、数据文件格式介绍
约 2859 个字 768 行代码 6 张图片 预计阅读时间 19 分钟
Info
这里默认以 Python 及基于此的模块介绍文件格式的读写、转换
如无特殊说明,均为默认情况,暂不考虑对解析器的定制
为什么用文件记录配置、数据?
- 与代码分离,便于部署
- 便于记录数据
- 便于不同程序之间交换
为什么用特定的文本文件格式?
- 有现成的解析工具
- 编辑器支持
- 文本格式便于编辑
常见的文件格式:
- CSV(
.csv
) - INI (
.ini
、.conf
、...) - JSON (
.json
) - YAML (
.yaml
、.yml
) - TOML (
.toml
) - XML (
.xml
)
CSV
逗号分隔值(Comma-Separated Values)
格式示例
-
实际上相当于表格,存储的是二维及以下的数据:
desc date 缺失1 缺失2 缺失3 缺失4 改善1 改善2 改善3 改善4 逾期1 逾期2 逾期3 逾期4 初始 3 0 1 1 0 0 0 0 0 0 0 0 13: 事业群1, D4.1, 一般, 延期 2023/1/1 0:00 3 0 1 1 0 0 0 0 1 0 0 0 12: 事业群2, D4.1, ""主要"", 延期 2023/1/1 0:00 3 0 1 1 0 0 0 0 1 0 0 0 11: 事业群1, D4.1, 关键, 关闭 2020/1/1 0:00 3 0 1 1 1 0 0 0 1 0 0 0 10: 事业群2, C5.1, 风险, 关闭 2020/1/1 0:00 3 0 1 1 1 0 0 0 1 0 0 0 7: 事业群1, C5.1, 一般, 延期 2023/1/1 0:00 3 0 1 1 1 0 0 0 2 0 0 0 9: 事业群1, C5.2, 主要, 未整改 3 0 1 1 1 0 0 0 3 0 0 0 8: 事业群2, C5.2, 关键, 延期 2023/1/1 0:00 3 0 1 1 1 0 0 0 3 0 0 0 4: 事业群2, C5.2, 一般, 关闭 2020/1/1 0:00 3 0 1 1 1 0 0 0 3 0 0 0 5: 事业群1, C5.2, 主要, 关闭 2020/1/1 0:00 3 0 1 1 1 0 0 0 3 0 0 0 6: 事业群2, C5.1, 关键, 未整改 3 0 1 1 1 0 0 0 3 0 0 0 2: 事业群2, B6.2, 一般, 关闭 2020/1/1 0:00 3 0 1 1 1 0 1 0 3 0 0 0 3: 事业群1, C5.1, 风险, 关闭 2020/1/1 0:00 3 0 1 1 1 0 1 0 3 0 0 0 1: 事业群1, A1.1, 风险, 延期 2023/1/1 0:00 3 0 1 1 1 0 1 1 3 0 0 1 -
可带标题行也可不带,但处理时要注意。
- 由于换行符的存在,一行不一定是表格中的一行。
- 常用于数据交换和存储。
变体
CSV 根据分隔符、换行方式、空内容表示方法、双引号表示方法、特殊字符处理方式等,可以分为多种变体。
常用的是 Excel 变体,格式如下:
- 以半角逗号分隔各列
- 如果内容有逗号或换行符,用半角双引号包裹
- 如果内容有半角双引号,则在前面的基础上双写内容中的半角双引号
- 一行的换行符为 CRLF(
\r\n
)
如果以制表符为分隔符,也可以称作 TSV。
Excel 处理 CSV
Excel 变体的 CSV 文件可用 Excel 打开、编辑、储存。
如果有小数,使用 Excel 打开后,精度可能有丢失。
保存时需要选择“CSV UTF-8”,而非“CSV”,否则会以系统默认编码(如 GBK、Big5)储存。
即便如此,存储格式实际上为 UTF-8 带 BOM 的格式,而许多程序默认的 UTF-8 编码不带 BOM,处理时会造成一些麻烦。
转换编码
大多数编辑器带此功能。以 Visual Studio Code 为例:
- 点状态栏的编码部分
- 如果打开的时候就有乱码,先选择“通过编码重新打开”,再选择可能的编码,如果正常,再继续
- 选择“通过编码保存”
- 选择需要存为的编码
Python 读 CSV
Python 有读写 CSV 的标准库 csv
。
一种读取方式是用 reader
函数读取,结果是一个 _csv.reader
对象,其可迭代。迭代结果中,每一行为列表,其中每一项为字符串,表示该行各列的值。
这种读取方式不会考虑是否有表头,表头会被当做第一行。
另一种读取方式为创建 DictReader
类,可迭代。
迭代结果中,每一行为字典。键为第一行各列值,即表头;值为各列值。
这种读取方式,第一行为表头。
CSV 文件转为以 Python 字典格式为项目的列表(不考虑错误处理等情况):
Python 写 CSV
写 CSV 时,要确保打开文件时定义参数 newline=''
,否则每写一行都会多一个空行。
使用 write
函数创建一个对象 _csv.writer
,用它的 writerow
和 writerows
方法写入行(前者为单行写入,后者为多行写入)。
写入行时,参数需可迭代。
Question
如果要更改 CSV 中某一行某一列的值,怎么做?
INI
initialization
格式示例
INI 是非正式标准,其变体非常多。
一般分若干节,每节有若干键值对,键和值之间用半角冒号或等号隔开,可用空格使文本美观。
存储的是二维及以下的数据。
常用于记录配置(MySQL、PHP)。
Python 读 INI
使用标准库 configparser
,使用其中的 ConfigParser
类实现读写。其尽可能为许多变体进行了适配。
节区分大小写,键不区分大小写。
DEFAULT
节可以配置各节的默认值。
任何情况下,值都被存储为字符串。
- 未定义的值存储为空字符串。
- 对于布尔值含义的文本,可以对节用
getboolean(键)
方法转换为布尔值。 - 对于整数和浮点数,除直接转换外,也可以相应地用
getint()
和getfloat()
方法。
./test.ini | |
---|---|
可以读多个配置,有冲突的键会被新的覆盖掉。
如果新读入默认配置,则会同步更改其他节的对应配置,但节内此前配置过的除外。
覆盖过程
test.ini | |
---|---|
-
初次从文件名读入
-
从字符串读入
-
从字典读入
-
再次从文件名读入
test2.ini
Python 写入 INI
用 ConfigParser
类的 write
方法写入。
传入文件对象,模式需为 w
。
test.ini | |
---|---|
JSON
JavaScript Object Notation
格式示例
和 Python 的字典、字典组成的列表很像,不过引号必须是双引号。
可以不换行不缩进以缩减体积,也可以换行缩进以保证美观。
支持的数据类型:
- 字符串
- 数字
- 布尔值
- null
- 对象(用大括号包裹)
- 列表(用方括号包裹)
可以通过嵌套表达多维的数据。
常用于数据交换,也可用于记录配置(Docker)。
Python 将其他数据类型转为 JSON
Python 有标准库 json
以读写 JSON 字符串。
使用 json.dumps(字典或列表)
转为字符串。
使用 json.dump(字典或列表, 文件对象)
转到文件。
Python 将 JSON 转为其他数据类型
使用 json.loads()
从字符串转。
使用 json.load()
从 IO(包括文件对象)转。
test.json | |
---|---|
YAML
YAML Ain't Markup Language
格式示例
依靠缩进表达层级(嵌套)关系,一般是两个空格。
列表各项可以以 -
加上空格开头。
可以写注释。
可以用 ---
分段,将多个文档写到一个文件中。
常用于记录配置(Docker Compose)。
Python 将其他数据类型转为 YAML
需要安装第三方模块,如 PyYAML。
直接写入文件:
将多条数据转为 YAML 字符串(这时字符串会包含多段;也可以转为文件):
test2.yml | |
---|---|
Python 将单段 YAML 转为其他数据类型
可以用 yaml.load()
处理,但要传入 Loader
参数。也可以直接使用 yaml.safe_load()
。
可以传入文件对象。
Python 将多段 YAML 转为其他数据类型
可以用 yaml.load_all()
处理,但要传入 Loader
参数。也可以直接使用 yaml.safe_load_all()
。
可以传入文件对象。
TOML
Tom 的(语义)明显、(配置)最小化的语言(Tom's Obvious, Minimal Language)
格式示例
样式很像 INI,但支持的功能更多。
不允许不写值。
详细的语法:https://toml.io/cn/v1.0.0。
常用于记录配置。
Python 将 TOML 转为字典
Info
新版的 Python 有处理 TOML 的标准库,编写该教程的时候,还没有。
以 pytomlpp
库为例:
从字符串读可以使用 pytomlpp.loads()
:
从文件读可以用 pytomlpp.load()
,传入文件对象:
Python 将字典转为 TOML
转为字符串用 pytomlpp.dumps(字典)
;转为文件用 pytomlpp.dump(字典, 文件对象)
。
XML
可扩展标记语言(EXtensible Markup Language)
格式示例
与 HTML 类似,不过可以自定义标签名、属性等。
以前常用于数据交换,现在也用于记录配置(Maven)。
Python 解析 XML
Python 标准库提供有 xml
,用于解析 XML,但如果 XML 有恶意代码,可能会存在安全问题。Python 官方文档推荐使用第三方的 defusedxml
模块替代,以提高安全性。
XML 的解析可以使用 DOM、SAX 和 ElementTree API 三种方法,这里只介绍 ElementTree API 的简单的方法。
使用 defusedxml.ElementTree.parse()
解析:
使用 defusedxml.ElementTree.parse(文件路径或文件对象)
解析为 ElementTree
对象,再对其使用 getroot()
方法获得 Element
对象。
使用 defusedxml.ElementTree.fromstring(字符串)
解析为 Element
对象。
对 Element
对象使用 find(XPath)
方法,返回第一个符合条件的对象。
使用 findall(XPath)
方法,返回所有符合条件的对象组成的列表。
使用 iter(标签名)
方法,可以生成一个生成器,可迭代所有为这个标签名的对象。
Python 写入 XML
可以对 ElementTree
、Element
对象进行新增、修改、删除等操作。
一些操作需要 xml
模块下的包。
使用 xmltodict
实现 XML 与字典互换
xmltodict
是第三方模块。
xmltodict.parse(字符串或文件对象)
可以将 XML 转换为字典。
- 如果传入文件对象,需确保以二进制形式打开。
- 默认情况下,如果有参数,则会成为标签下的键,键为
@
加上参数名;这种情况下,如果有文本,则会成为标签下的键,键为#text
。
xmltodict.unparse(字典)
可以将字典转换为 XML。对字典格式有要求。
总结
文件格式 | CSV | INI | JSON | YAML | TOML | XML |
---|---|---|---|---|---|---|
使用的模块 | csv |
configparser |
json |
yaml |
pytomlpp |
xml ; defusedxml |
是否是标准库 | 是 | 是 | 是 | 否 | 否 | 是;否 |
从数据读 | .ConfigParser() > .read_string(字符串) 或 .read_dict(字典) |
.loads(字符串) → 字典、列表等 |
.safe_load(字符串) → 字典、列表等 |
.loads(字符串) → 字典 |
.ElementTree.fromstring(字符串) → Element |
|
从文件读(里面的“流”可以用文件对象指代) | .reader(流) 或 .DictReader(流) |
.ConfigParser() > .read(文件名) |
.loads(流) → 字典、列表等 |
.safe_load(流) → 字典、列表等 |
.load(流) → 字典 |
.ElementTree.parse(文件路径或流) → ElementTree |
写到数据 | .dumps(字典或列表, ...) → 字符串 |
.dump(字典或列表, ...) → 字符串 |
.dumps(字典) → 字符串 |
xml.etree.ElementTree.dump() → 字符串 |
||
写到文件(里面的“流”可以用文件对象指代) | .writer(流) > .writerow(一行的列表) 或 .writerows(包含各行的列表) |
.ConfigParser() > .write(流) |
.dump(字典或列表,流, ...) |
.dump(字典或列表,流, ...) |
.dump(字典, 流) |
.ElementTree.parse() > .write(文件路径或流) |
参考资料
- Python操作CSV格式文件的方法大全_python_脚本之家
- csv --- CSV 文件读写 — Python 3.10.5 文档
- configparser --- 配置文件解析器 — Python 3.10.5 文档
- RFC 7159 - The JavaScript Object Notation (JSON) Data Interchange Format
- The Official YAML Web Site
- python yaml用法详解_EastonLiu的博客-CSDN博客_python yaml
- yaml/pyyaml: Canonical source repository for PyYAML
- toml-lang/toml: Tom's Obvious, Minimal Language
- TOML: 简体中文 v1.0.0
- 现实生活中的 XML
- XML处理模块 — Python 3.10.5 文档
- defusedxml · PyPI
- xml.etree.ElementTree --- ElementTree XML API — Python 3.10.5 文档