.py
直接使用python存储配置信息,通常使用字典数据类型。
# python
{
'id': 1,
'name': "Jason",
'human': True,
'hobbies': [
'eating',
'playing',
],
'features': {
'assets': None,
'weight': 60,
},
}
{
"id": 1,
"name": "Jason",
"human": true,
"hobbies": [
"eating",
"playing"
],
"features": {
"assets": null,
"weight": 60
}
}
.ini
INI
INI(Initialization File)是Windows系统中最常见的配置文件格式,它使用键值对的形式存储配置信息。通常只支持字符串类型,虽然一些解析器可能支持其他类型,但这不是标准的INI格式。不支持复杂的数据结构,扩展性较差,不适合表示复杂或层次深的数据。
INI语法细节
INI文件由节(sections)、键(keys)和值(values)组成。节由方括号包围的节名表示,键和值成对出现,用等号或冒号分隔。
[Profile]
name=Jason
age=18
hobbies=eating,playing
{
"Profile": {
"name": "Jason",
"age": 18,
"hobbies": "eating,playing"
}
}
.json
JSON
JSON(JavaScript Object Notation) 一种人类可读的文本数据格式。它源于 JavaScript、标准开放、独立于具体编程语言、常用于数据交换。
JSON标准中一共定义了六种值类型
数据类型(Type) | 示例(Example) |
---|---|
数组(Array) | [值1, 值2, 值3, ...] |
布尔值(Boolean) | true, false, null |
数值(Number) | 100, 3.14, -20 |
对象(Object) | {字符串: 值, 字符串: 值, ...} |
字符串(String) | "一定要用双引号包裹" |
// javascript
{
id: 1,
name: "Jason",
human: true,
hobbies: [
'eating',
'playing',
],
features: {
assets: null,
weight: 60,
},
}
通过将其中的所有单引号换为双引号,将对象中的键名改为由双引号包裹的同名字符串,再将对象与数组中最后出现的多余逗号去掉,我们便可以得到与其相对应的JSON数据。
{
"id": 1,
"name": "Jason",
"human": true,
"hobbies": [
"eating",
"playing"
],
"features": {
"assets": null,
"weight": 60
}
}
# python
{
'id': 1,
'name': "Jason",
'human': True,
'hobbies': [
'eating',
'playing',
],
'features': {
'assets': None,
'weight': 60,
},
}
Python字典与JSON格式的主要区别
- 字符串键:在JSON中,对象(类似于Python的字典)的键必须是字符串。虽然在Python 3.6+中,字典会保留插入的顺序,但在Python 3.6之前,字典是无序的,而在JSON中,对象的键总是被认为是有序的。
- 字符串引号:在JSON中,字符串必须使用双引号(")包裹。在Python中,你可以使用单引号(')、双引号(")或三引号('''或""")。
- 数据类型:JSON支持的数据类型包括字符串、数字(整数和浮点数)、布尔值(true/false)、数组(类似于Python的列表)、对象(类似于Python的字典)和null。Python字典的值可以是任何数据类型,包括字符串、数字、列表、字典、元组、集合等。对于布尔值和空值类型,JSON使用true/false/null,而Python的True/False/None。
- 注释:Python字典允许在源代码中添加注释,而JSON不支持注释。
- 尾随逗号:在Python中,字典的键值对可以有一个尾随逗号,而在标准的JSON中,尾随逗号是不允许的(尽管在某些实现中可能被宽容处理)。JSON 5是一个JSON的扩展,它允许尾随逗号。
- 复杂对象:Python字典可以包含任何Python对象,包括函数、类实例等。而JSON只能表示简单的数据结构。
JSON 5
JSON 5
JSON 5是一个JSON的扩展,它增加了对一些JavaScript对象字面量特性的支持,例如注释、尾随逗号、单引号字符串等。这使得JSON 5更容易阅读和编写,同时也更易于与JavaScript对象字面量互相转换。
尽管JSON 5提供了更多的灵活性和便利性,但它并不是一个官方的ECMAScript标准,因此在某些环境下可能不被支持。
{
// json5
id: 1, // 属性名没有双引号,尾随逗号
name: "Jason",
human: true,
hobbies: [
'eating',
'playing', // 数组尾部的尾随逗号
],
features: {
assets: null, // 对象尾部的尾随逗号
weight: 60,
},
}
.yaml
YAML
YAML(Yet Another Markup Language / YAML Ain't Markup Language)不再是一种标记语言,而是一种人类可读的数据序列化语言,它常用于配置文件,可被多种编程语言解析。YAML的定位与JSON相近,但具有自己的特色。
YAML语法细节
字符串(String)
Jason
"Jason"
'Jason'
"Jason"
列表(List)
- Jason
- 18
[Jason, 18,]
[
"Jason",
18
]
关联数组(Associative Array)
name: Jason
age: 18
{name: Jason, age: 18,}
{
"name": "Jason",
"age": 18
}
缩进结构(Indentation)
Profile:
name: Jason
age: 18
hobbies:
- eating
- playing
Profile:
name: Jason
age: 18
hobbies:
- eating
- playing
Profile:
name: Jason
age: 18
hobbies:
- - eating
- playing
{
"Profile": {
"name": "Jason",
"age": 18,
"hobbies": [
"eating",
"playing"
]
}
}
{
"Profile": null,
"name": "Jason",
"age": 18,
"hobbies": [
"eating",
"playing"
]
}
{
"Profile": {
"name": "Jason",
"age": 18
},
"hobbies": [
[
"eating",
"playing"
]
]
}
注释(Comment)
Profile: # 这是一条注释
name: Jason
age: 18
{
"Profile": {
"name": "Jason",
"age": 18
}
}
区块字符(Block Character)
Profile:
I'm Jason,
in Shanghai.
{
"Profile": "I'm Jason, in Shanghai."
}
# 保留换行
Profile: |
I'm Jason,
in Shanghai.
{
"Profile": "I'm Jason,\nin Shanghai.\n"
}
# 折叠换行
Profile: >
I'm Jason,
in Shanghai.
{
"Profile": "I'm Jason, in Shanghai.\n"
}
# 去掉末尾换行符
Profile: |-
I'm Jason,
in Shanghai.
{
"Profile": "I'm Jason,\nin Shanghai."
}
# 保留末尾换行符
Profile: >+
I'm Jason,
in Shanghai.
{
"Profile": "I'm Jason, in Shanghai.\n\n"
}
锚点与引用(Anchor & Reference)
name: Jason
age: name
addr: &addr Shanghai
ship-to: *addr
{
"name": "Jason",
"age": "name"
"addr": "Shanghai",
"ship-to": "Shanghai"
}
标签(Tag)
name: Jason
age: 18
money: !!str null
# 全局标签
!! str
!<tag:yaml.org,2002:str>
# 本地标签
!str
!<!str>
# 控制标签解析行为
%TAG ! tag:yaml.org,2002:
---
name: Jason
age: 18
money: !str null
{
"name": "Jason",
"age": 18,
"money": "null"
}
文档(Doc)
%TAG ! tag:yaml.org,2002:
--- # 文档开始
name: Jason
age: 18
money: !str null
... # 文档结束
--- # 另一个文档开始
name: Alice
age: 24
money: 1000
... # 另一个文档结束
{
"name": "Jason",
"age": 18,
"money": "null"
}
{
"name": "Alice",
"age": 24,
"money": 1000
}
YAML支持
语言 | 库 |
---|---|
C/C++ | LibYAML |
Go | go-yaml |
Java | jvyaml / JYAML |
JavaScript | eemeli/yaml |
Python | PyYAML |
Objective-C | Cocoa-Syck |
C# | YamlDotNet |
YAML 比较 JSON 的优势
更方便的文本内联
html: >-
<p class="tag">
Jason
</p>
{
"html": "<p class=\"tag\">\n Jason\n </p>"
}
更易读的数据关系
addr: &addr Shanghai
ship-to: *addr
{
"addr": "Shanghai",
"ship-to": "Shanghai"
}
YAML 比较 JSON 的劣势
复杂语法结构
%TAG !yaml! tag:yaml.org,2002:
---
omap: !yaml!omap
- name: Jason
- humal: !!bool true
- date: 2024-09-10
- ? money
{
"omap": [
{
"name": "Jason"
},
{
"humal": true
},
{
"date": "2024-09-10T00:00:00.000Z"
},
{
"money": null
}
]
}
容易形成RCE漏洞
!!python/object/apply:subprocess.Popen
- - echo
- "You have been hacked :)"
# PyYAML
from yaml import load, Loader
# ...
result = load(
request.from['file'],
Loader=Loader
)
print(result)
.toml
TOML
TOML(Tom's Obvious, Minimal Language)是Tom Preston-Werner在2013年发明的一种语义明确、配置最小化语言,旨在成为一个小规模、易于使用的语义化配置文件格式,它被设计为可以无二义性地转换为一个哈希表。
语法细节
键值对(Key/Value Pair)
name = "Jason"
age = 18
addr = "Shanghai" # 缩进不影响
profile.age = 18 # 点表示嵌套
profile.addr = "Shanghai"
about.pets.cats = "Pipi"
# profile = "Jason" # 错误,键名不能重复
{
"name": "Jason",
"age": 18,
"addr": "Shanghai",
"profile": {
"age": 18,
"addr": "Shanghai"
},
"about": {
"pets": {
"cats": "Pipi"
}
}
}
字符串(String)
name = "Jason"
name2 = """Jason
Yu
"""
name3 = """
Jason \
Yu\
"""
name4 = 'Jason\nYu'
name5 = '''
Jason
Yu
'''
{
"name": "Jason",
"name2": "Jason\nYu\n",
"name3": "Jason Yu",
"name4": "Jason\\nYu\n",
"name5": "Jason\nYu\n"
}
数组(Array)
hobbies = [
"eating",
"playing",
]
hobbies2 = [
[
"eating",
"playing",
]
]
{
"hobbies": [
"eating",
"playing"
],
"hobbies2": [
[
"eating",
"playing"
]
]
}
表(Table)
profile.age = 18
profile.addr = "Shanghai"
profile.jobs.EfficLab = true
about.pets.cats = "Pipi"
[profile]
age = 18
addr = "Shanghai"
jobs = { EfficLab = true } # 内联表 只能写在一行
[about.pets]
cats = "Pipi"
# [about.pets] # 错误,表名与键名都不能重复定义
{
"profile": {
"age": 18,
"addr": "Shanghai",
"jobs": {
"EfficLab": true
}
},
"about": {
"pets": {
"cats": "Pipi"
}
}
}
表数组(Array of Tables)
[[profile]]
name = "Jason"
age = 18
[[profile]] # 不同与表 表数组可以重复定义
name = "Alice"
age = 20
profile = [
{ name = "Jason", age = 18 },
{ name = "Alice", age = 20 }
]
{
"profile": [
{
"name": "Jason",
"age": 18
},
{
"name": "Alice",
"age": 20
}
]
}
注释(Comment)
# 单行注释
name = "Jason" # 这是一个注释
{
"name": "Jason"
}
使用限制
顶层表数据无法后置
name = "Jason"
[profile]
age = 18
addr = "Shanghai"
{
"name": "Jason",
"profile": {
"age": 18,
"addr": "Shanghai"
}
}
[profile]
age = 18
addr = "Shanghai"
name = "Jason" # 会被归类到 profile 表
{
"profile": {
"age": 18,
"addr": "Shanghai",
"name": "Jason"
}
}
内联表无法换行
profile = [
{ name = "Jason", age = 18 },
{ name = "Alice", age = 20 },
]
{
"profile": [
{
"name": "Jason",
"age": 18
},
{
"name": "Alice",
"age": 20
}
]
}
可读性依赖于写法
[profile]
age = 18
addr = "Shanghai"
name.surname = "Yu"
[[pets.cat]]
name = "Pipi"
[about]
job = "EfficLab"
[pets.cat.children]
[about.desc]
skill = "CS"
{
"profile": {
"age": 18,
"addr": "Shanghai",
"name": {
"surname": "Yu"
}
},
"pets": {
"cat": [
{
"name": "Pipi",
"children": {}
}
]
},
"about": {
"job": "EfficLab",
"desc": {
"skill": "CS"
}
}
}