网络爬虫 ------ 配置文件解析
ini
ini
( Initialization File
)顾名思义,主要用于初始化应用程序。这是一种无固定标准格式的配置文件,且文件没有固定的后缀,常见的有 .ini
、 .conf
、.cfg
,甚至还可以是 .txt
。主要用于 Windows
操作系统上,但也有很多程序会采用 INI
文件作为配置文件使用。
文件格式
ini
格式在不同的解析器中会具有不同的特征,比较固定的是:
- 节:使用中括号包裹的字符串,其后面的所有参数(到下一个小结的开始之前),都归属于该节
ini
[section]
- 参数:以键值对的方式设置参数值,即程序中需要访问的参数所对应的值
ini
name = value
- 注释:以
;
或#
开头的行表示的是注释信息
ini
; comment text
# comment line
- 大小写不敏感
section
中的参数顺序与其在文件中出现的顺序无关
除了上面的基本特征之外,不同的解析器可能还提供了
- 全局属性
- 冒号(
:
)或空格分隔的键值对声明方式 - 层次或嵌套形式的
section
- 重复参数名称
- 参数引用等
示例
在 demo.ini
中输入下面的文本并保存
ini
[DEFAULT]
; default directory
path = /usr/bin
# P value cut off
cut_off = 0.05
[PROGRAMS]
python = /path/to/python
R = /path/to/R
R 解析文件
在 R
中,我们使用 configr
包来读写常见的 4
种配置文件,该包是对 ini
、jsonlite
、yaml
和 RcppTOML
这 4
个包的封装,内核还是通过调用它们来对不同格式的文件进行解析的。
首先需要安装该包
r
# CRAN
install.packages('configr')
# Github
# install.packages("devtools")
devtools::install_github("Miachol/configr")
导入包
r
library(configr) # version 0.3.5
读取文件
使用 read.config
函数即可读取文件
r
conf <- read.config("demo.ini")
class(conf)
# [1] "list"
str(conf)
# List of 2
# $ DEFAULT :List of 2
# ..$ path : chr "/usr/bin"
# ..$ cut_off: chr "0.05"
# $ PROGRAMS:List of 2
# ..$ python: chr "/path/to/python"
# ..$ R : chr "/path/to/R"
该函数返回一个嵌套的 list
对象,第一层为节,第二层为参数值。可以在程序中以访问 list
的形式获取配置文件中的参数信息。
该解析器提供了一些额外的特征,通过预先在文件中设置一些占位符,并在占位符中添加相应的命令,然后在读取时进行解析。主要通过几个参数来控制
参数 | 功能 |
---|---|
extra.list |
用字符串 list 来替换 {``{}} 包裹的字符 |
other.config |
导入其他配置文件 |
rcmd.parse |
是否将 @>@ 包裹的字符串作为 R 命令执行 |
bash.parse |
是否将 #># 包裹的字符串作为 bash 命令执行 |
glue.parse |
是否执行 glue 命令 |
glue.flag |
设置 glue 命令的起始标志,默认为 !!glue |
demo.ini
文件里面写入如下内容
ini
[DEFAULT]
debug = {{debug}}
[other]
name = {{others:name}}
[rcmd_parse]
time = @>@ Sys.Date() @<@
[bash_parse]
home = #>#echo $HOME#<#
[mulitple_parse]
multi = @>@str_replace('config','g$','gr')@<@, #>#echo configr#<#, {{others:name}}
[glue_parse]
range_chr = !!glue {1:10}
range_num = !!glue_numeric {1:10}
在 other.ini
中添加如下内容
ini
[others]
name = Tom
读取并解析
r
conf <- read.config("demo.ini", extra.list = list(debug = "true"),
other.config = "other.ini", rcmd.parse = TRUE,
bash.parse = TRUE, glue.parse = TRUE)
str(conf)
# List of 6
# $ DEFAULT :List of 1
# ..$ debug: chr "true"
# $ other :List of 1
# ..$ name: chr "Tom"
# $ rcmd_parse :List of 1
# ..$ time: chr "2022-10-07"
# $ bash_parse :List of 1
# ..$ home: chr "/Users/dengxsh"
# $ mulitple_parse:List of 1
# ..$ multi: chr "configr, configr, Tom"
# $ glue_parse :List of 2
# ..$ range_chr: chr [1:10] "1" "2" "3" "4" ...
# ..$ range_num: num [1:10] 1 2 3 4 5 6 7 8 9 10
写入文件
一般情况下,都是手动创建配置文件,很少会将数据直接写入到配置文件中,除非需要自动化创建默认的配置文件。我们可以将 list
对象写入到配置文件中,例如
r
data <- list(
user = list(username = "admin", passwd = "123456"),
info = list(type = "init")
)
write.config(config.dat = data, file.path = "test.ini", write.type = "ini")
在 test.ini
中将会看到如下内容
ini
[user]
username=admin
passwd=123456
[info]
type=init
Python 解析文件
在 Python
中,我们可以使用标准库中的 configparser
包来解析 ini
格式的配置文件。例如,创建如下名为 setting.ini
的配置文件
ini
[default]
path = /default/path
[server]
address = 127.0.0.1
port = 8080
导入包并创建配置解析器
python
import configparser
config = configparser.ConfigParser()
使用配置解析器来读取配置文件
python
config.read('setting.ini')
# ['setting.ini']
config.sections() # 获取所有 section
# ['default', 'server']
config['default']['path'] # 获取属性值
# '/default/path'
我们可以将配置解析器当做字典来使用,其具有字典的一般行为,但也存在一些差异。例如,解析器支持同时传入 section
和属性名称来获取属性值。
配置解析器并不会自动推测配置文件中值的类型,总是将它们存储为字符串,我们可以手动转换或使用解析器提供的便捷函数
python
config['server'].get('port')
# '8080'
int(config.get('server', 'port'))
# 8080
config.getint('server', 'port')
# 8080
除了 getint
之外,还有 getfloat
和 getboolean
,get
函数也可以提供默认值。
python
config['server'].get('name', 'Tom')
# 'Tom'
该解析器也支持一些特性,例如
- 支持冒号
:
声明键值对 - 支持配置文件内插值,值可以在被
get
调用返回之前进行预处理
我们在配置文件中 setting.ini
添加如下内容
ini
[Paths]
home_dir: /Home/user
my_dir: %(home_dir)s/my
my_pictures: %(my_dir)s/Pictures
percent: 80%%
其中 %(home_dir)s
将会替换为 home_dir
属性的值,%%
会替换为百分号 %
python
config.read('setting.ini')
config.sections()
# ['default', 'server', 'Paths']
config.get('Paths', 'my_dir')
# '/Home/user/my'
config.get('Paths', 'my_pictures')
# '/Home/user/my/Pictures'
config.get('Paths', 'percent')
# '80%'
自定义解析器
ini
格式的变种非常多,默认的解析器只具备一些常用的功能,我们可以在创建解析器是指定一些行为。例如
allow_no_value
参数可用于指明是否接受不带值的属性delimiters
用于指定分隔键和值的子字符串comment_prefixes
注释的前缀interpolation
用于指定插值方式,可以使用ExtendedInterpolation
类指定更高级的语法,或使用None
来禁用插值语法
扩展插值插值可以跨越多个层级,使用方式形如 ${section:option}
,如果省略 section:
,则表示作用于当前小节。例如,对如下配置文件进行解析
ini
[default]
path = /Home/user
[Paths]
my_dir: ${default:path}/my
my_pictures: ${my_dir}/Pictures
[Others]
money: $$80
python
config = configparser.ConfigParser(
interpolation=configparser.ExtendedInterpolation()
)
config.read('setting.ini')
config.get('Paths', 'my_dir')
# '/Home/user/my'
config.get('Others', 'money')
# '$80'
写入文件
我们可以使用类似于为字典赋值的方式,为解析器添加配置,例如
python
config['Others'] = {
'name': 'Tom',
'age': 28
}
config['default']['salary'] = '10000'
写出解释器对象的值
python
with open('setting.ini', 'w') as configfile:
config.write(configfile)
setting.ini
中的内容将变为
ini
[default]
path = /Home/user
salary = 10000
[Paths]
my_dir = ${default:path}/my
my_pictures = ${my_dir}/Pictures
[Others]
name = Tom
age = 28
json
json
(JavaScript Object Notation
)是一种开放的标准文件格式,易于机器创建和解析,是一种实用的轻量级数据交换格式。虽然它起源于 JavaScript
,但它独立于 JavaScript
,现在很多语言都提供了相应的包来用于处理这种类型的数据。一些生物数据库也会将数据存储为 json
格式,便于解析。
文件格式
json
文件的格式包含两种,可以理解为将 Python
中的字典或列表直接存储到文件中,例如
字典形式的文件格式(dict.json
)
json
{
"name": ["John"],
"age": [19],
"children": ["Catherine", "Thomas", "Trevor"]
}
列表形式的文件格式(list.json
)
json
[
{"name": "Tom", "age": 18},
{"name": "Jim", "age": 20}
]
R 解析文件
R
中有几个用于解析 json
的包,上面的 configr
也可以,使用方法一样,只需将文件类型参数改为 json
即可
r
read.config("dict.json", file.type = "json")
读取 json
文件时,会根据 json
里面的数据内容自动将其转换为 list
或 data.frame
类型,例如
r
j <- read.config("Downloads/dict.json", file.type = "json")
str(j)
# List of 3
# $ name : chr "John"
# $ age : int 19
# $ children: chr [1:3] "Catherine" "Thomas" "Trevor"
read.config("Downloads/list.json", file.type = "json")
# name age
# 1 Tom 18
# 2 Jim 20
可以将 list
或 data.frame
数据转换为 json
对象,pretty
参数用于控制是否美化输出
r
d <- data.frame(
name = c("Tom", "Jim"),
age = c(18, 20)
)
write.config(d, "Downloads/list.json", write.type = "json")
# [1] TRUE
Python 解析文件
Python
标准库提供了 json
包可以用于处理 json
数据,可以将文件其转换为内置的 list
或 dict
类型对象。
使用 load
函数导入文件对象中的数据
python
import json
json.load(open("dict.json"))
# {'name': 'John', 'age': 19, 'children': ['Catherine', 'Thomas', 'Trevor']}
或者使用 dump
函数将数据写入到文件中
python
data = [
{"name": "Tom", "age": 18},
{"name": "Jim", "age": 20}
]
json.dump(data, open('list.json', 'w'))
可直接将字典或列表数据写入文件中,导入数据时也会自动解析为字典或列表类型的对象。这两个函数分别有一个加 s
的版本,用于处理对象与字符串之间的转换,如
python
json.dumps(data)
# '[{"name": "Tom", "age": 18}, {"name": "Jim", "age": 20}]'
d = '{"name": "John", "age": 19, "children": ["Catherine", "Thomas", "Trevor"]}'
json.loads(d)
# {'name': 'John', 'age': 19, 'children': ['Catherine', 'Thomas', 'Trevor']}
注意,将 json
格式的字符串转换为对象,其中的字符串需要为双引号。同时,在转换时也可以设置输出格式,设置缩进的空格数 (indent
),或者对键进行排序(sort_keys
)
python
j = json.dumps(data, indent=4, sort_keys=True)
print(j)
# [
# {
# "age": 18,
# "name": "Tom"
# },
# {
# "age": 20,
# "name": "Jim"
# }
# ]
yaml
YAML
(Yet Another Markup Language
) 是一种数据序列化的语言,以数据为中心,且更注重于数据的描述和展示。其可读性高、易于理解,可灵活地与其他编程语言结合使用。相较于前面两种文件格式,其既可以定义复杂的结构化数据,也支持注释、属性引用等,还可以引用其他配置文件,降低代码的冗余。
基本语法
yaml
中数据类型的概念与其他高级编程语言类似,包括三种数据类型
- 数组(列表)
- 映射(字典或哈希)
- 标量(包括字符串、整数和浮点数等)。
yaml
是大小写敏感的,使用与 Python
类似的缩进(使用空格而不是 TAB
控制缩进)来表示数据的层级关系(一般不使用括号或引号)、键值对使用冒号作为分隔标识(冒号后面必须紧跟一个空格)、#
符号之后的内容作为注释不会被解析。文件后缀推荐使用 .yaml
,也有人会使用 .yml
作为文件后缀。
其与 json
格式非常类似,可以认为是 json
的超集,在 yaml
文件中也可以使用 json
的语法。
例如,我们定义如下关系映射数据
yaml
server: # web server
name: work
host: 127.0.0.1
port: 8080
注意,缩进的空格数没有限制,只要保证同一层级中所有的元素左对齐即可。上面的内容将被解析为
python
{'server': {'name': 'work', 'host': '127.0.0.1', 'port': 8080}}
上面文件的内容也可以写在一行,但需要使用花括号包裹起来
yaml
server: {name: work, host: 127.0.0.1, port: 8080}
数组使用横杠 -
标识每一个元素(横杠后面必须紧跟一个空格),例如
yaml
address_list:
- 127.0.0.1
- 192.168.0.1
- 0.0.0.0
上面的内容将被解析为
python
{'address_list': ['127.0.0.1', '192.168.0.1', '0.0.0.0']}
列表也可以写在一行内,但是需要用方括号包裹起来
yaml
address_list: [127.0.0.1, 192.168.0.1, 0.0.0.0]
如果要在一个文件中编写多个文档,可以使用三横杠 ---
来标识文档的开始,三个点 ...
来标识文档的结束。例如
yaml
---
name: Sam
age: 20
weight: 60kg
...
---
name: Ban
age: 21
weight: 55kg
...
在 yaml
文件中,字符串并不需要用使用引号,如果存在转义字符可以用双引号将字符串包裹,而单引号只能用两个单引号来转义自身,即 'don''t'
会被解析为 "don't"
。而对于多行文本,有两个字符可以指定不同的行为
|
:多行内容之间保留插入的换行符>
:多行内容之间使用空格连接
yaml
preserve: |
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
fold: >
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
两种模式中字符串将被解析为
python
{'preserve': 'Beautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\n',
'fold': 'Complex is better than complicated. Flat is better than nested. Sparse is better than dense.'
}
变量引用
如果要引用前面定义的变量,可以使用 &
先对元素进行锚定,在需要引用的地方使用 *
来引用之前锚定的内容,可以在锚定时指定相应的名称。例如
yaml
Sam:
name: Sam
age: &a 20
hobby:
- &s1 football
- sing song
Ben:
name: Ben
age: *a
hobby:
- *s1
对于键值对映射的元素需要在冒号之后添加锚定,对于列表元素,则在值之前添加锚定。
锚定与合并标签(<<
)搭配使用,可以将任意数据进行合并,例如
yaml
person: &base
name: null
age: 0
sam:
name: Sam
<<: *base # 引用锚点,实例化时会自动展开
hobby: # 添加额外的属性
- football
tom:
<<: *base # 引用锚点,实例化时会自动展开
name: Tom # 覆盖属性,相同属性是允许的但只会取最后一次的值
age: 10
上面的文件将被解析为
json
{
'person': {'name': None, 'age': 0},
'sam': {'name': 'Sam', 'age': 0, 'hobby': ['football']},
'tom': {'name': 'Tom', 'age': 10}
}
数据类型
一般我们读取文件时,会自动解析数据的类型,我们也可以在文件中使用双感叹号加类型名称的方式(如 !!str
)强制转换数据的类型,主要包含如下类型
标记 | 类型 | 标记 | 类型 |
---|---|---|---|
!!int |
整数类型 | !!float |
浮点类型 |
!!bool |
布尔类型 | !!str |
字符串类型 |
!!binary |
二进制字符串 | !!timestamp |
日期时间类型 |
!!null |
空值 | !!set |
集合类型 |
!!omp ,!!pairs |
配对列表 | !!map |
键值对 |
!!seq |
列表 |
例如,对于下面的文件内容
yaml
Stu: !!map
name: !!str Sam
age: !!float 20
boy: !!bool yes
Info: !!seq
- name
- age
- boy
将被解析为
python
{'Stu': {'name': 'Sam', 'age': 20.0, 'boy': True},
'Info': ['name', 'age', 'boy']}
R 解析文件
在 R
中操作 yaml
文件,也是使用 configr
包的 read.config
函数。对于如下文件 demo.yaml
yaml
- Sam:
age: 19
hobby:
- football
- sing song
- Tom:
age: 19
hobby:
- football
- TV
文件将会被解析为一个 list
,如果在读取时抛出了 readLines
函数的警告信息,可以忽略,或者在文件最后一行添加一个空行即可。
r
y <- read.config("demo.yaml", file.type = "yaml")
str(y)
# List of 2
# $ :List of 1
# ..$ Sam:List of 2
# .. ..$ age : int 19
# .. ..$ hobby: chr [1:2] "football" "sing song"
# $ :List of 1
# ..$ Tom:List of 2
# .. ..$ age : int 19
# .. ..$ hobby: chr [1:2] "football" "TV"
与前面类似,也可以将一个数据框写出为 yaml
文件
r
write.config(d, "dump.yaml", write.type = "yaml")
dump.yaml
文件中的内容为
yaml
name:
- Tom
- Jim
age:
- 18.0
- 20.0
Python 解析文件
在Python
中我们可以使用第三方包 PyYAML
来解析 yaml
文件,可直接使用 pip
进行安装
bash
pip install pyyaml # version 6.0
如果文件中只有一个文档,可以使用 load
函数或 safe_load
python
import yaml
from yaml import CLoader
yaml.load(open('demo.yaml'), CLoader)
# yaml.safe_load(open('demo.yaml'))
# [{'Sam': {'age': 19, 'hobby': ['football', 'sing song']}},
# {'Tom': {'age': 19, 'hobby': ['football', 'TV']}}]
如果一个文件里面有多个文档,则需要使用 load_all
,该函数将返回一个生成器
python
for data in yaml.load_all(open('demo.yaml'), CLoader):
print(data)
如果要将一个对象序列化为 yaml
文件,则可以使用 dump
函数
python
data = {
'name': 'Tom',
'age': 30,
'hobby': ['football', 'TV']
}
yaml.dump(data, open('dump.yaml', 'w'))
或者写入多个文档
python
yaml.dump_all([data, 1, 2, 3], open('dump.yaml', 'w'))
TOML
TOML
(Tom's Obvious, Minimal Language
) 的设计宗旨在于创建一种语义明确且易于阅读的最精简配置文件格式,其语法有点类似于 INI
文件格式,但它加了更多的规范来进行限定,这些规范包括一系列的数据类型:字符串、整数、浮点数、布尔值、日期时间、数组和表。其文件后缀为 .toml
。
基本语法
与 yaml
类似,toml
也是大小写敏感的,使用 #
来添加注释,也是以键值对的形式来定义属性,但是其不依赖缩进,且不属于属性名或属性值的空格都会被忽略掉。
键值对使用的是 =
来进行声明,例如
toml
key = "value" # this is first comment
键名可以是裸露的或使用引号包裹的字符串,即可分为裸键和引号键。有效的裸键必须为字符集 A-Za-z0-9_-
中的字符组成,引号键可以定义更加广泛的名称。注意,裸键加引号与不加引号本质是一样的,会被当做同一个属性,且同一个键不能被重复赋值。
toml
a-b = "123"
123 = "abc"
键名可以是空字符串,但是不推荐使用,也没人会在实际项目中这么用。
键名中如果存在 .
号,表示嵌套层级,例如
toml
person.name = 'Tom'
person.age = 20
person.'major' = 'chinese'
与下面的 json
表示同样的内容,会将 .
之后的名字作为子键名,与后面的表结构所表示的内容相似
json
{'person': {'name': 'Tom', 'age': 20, 'major': 'chinese'}}
字符串类型
字符串可分为 4
种类型,分别用不同的符号来表示:
- 基本字符串使用双引号(
"
) - 多行字符串使用三个双引号(
"""
) - 单行字面量使用单引号(
'
) - 多行字面量使用三个单引号(
'''
)
字符串的值只能是有效的 UTF-8
字符,例如
toml
str1 = "abc\tbcd\n"
str2 = """
Beautiful is better than ugly. \
Explicit is better than implicit.
Simple is better than complex.
"""
打印字符串之后,转移字符将会发挥作用,同时在多行字符串中,行尾的 \
表示将两行连接起来,即忽略后面的换行符。
abc bcd
Beautiful is better than ugly. Explicit is better than implicit.
Simple is better than complex.
对于字符串字面量
toml
str3 = 'abc\tbcd\n'
str4 = '''
a\tb\ncd \
efg\nh
'''
所有字符不会被转义,而是原样输出
abc\tbcd\n
a\tb\ncd \
efg\nh
整数类型
整数类型的数据,可以使用 +
和 -
来标识正负数,如果是较大的数值,可以使用 _
来分隔数字提高可读性,也可以使用不同进制形式的数值。例如
toml
a = 3
b = 1_000 # 千分位分隔
c = 0xDEADBEEF # 十六进制
d = 0o12345 # 八进制
e = 0b101001 # 二进制
文件将被解析为
python
{'a': 3, 'b': 1000, 'c': 3735928559, 'd': 5349, 'e': 41}
浮点类型
浮点类型的数值与整数类似,只是分为整数部分和小数部分,注意,两部分都不能省略。也支持科学计数法,下划线分隔等,例如
toml
a = 3.1415
b = 2.1e12
c = inf
d = nan
e = 3.141_592_653
将被解析为
python
{'a': 3.1415, 'b': 2100000000000.0, 'c': inf, 'd': nan, 'e': 3.141592653}
布尔与时间日期
布尔类型使用小写
toml
a = true
b = false
时间日期格式
toml
a = 09:32:03
b = 1997-07-01
c = 1941-08-14T08:23:10
在 Python
中会被解析为相应的时间日期格式
python
{'a': datetime.time(9, 32, 3),
'b': datetime.date(1997, 7, 1),
'c': datetime.datetime(1941, 8, 14, 8, 23, 10)}
数组
这里的数据基本相当于 Python
中的 list
类型,可以混合任意类型的数据,元素之间多余的空格和换行都会被忽略。例如
toml
ints = [1, 2, 3]
strs = ["a", "b"]
nest_arr = [
[1, 2],
[3, 4, 5]
]
mix = [0.1, 1, 'a', [2, "b"]]
解析为
python
{'ints': [1, 2, 3],
'strs': ['a', 'b'],
'nest_arr': [[1, 2], [3, 4, 5]],
'mix': [0.1, 1, 'a', [2, 'b']]}
哈希表
哈希表或字典类型,使用方括号里面加表名的方式作为表头来声明,与 ini
中的节类似,其作用范围从该表头至下一个表头或文件结束。例如
toml
[table]
name = "Tom"
age = 10
在 Python
中将被解析为嵌套字典
python
{'table': {'name': 'Tom', 'age': 10}}
表名可以像键名一样,使用 .
来创建嵌套哈希表,例如
toml
[table.person]
name = "Tom"
age = 10
解析为 table
表下面的 person
子表
python
{'table': {'person': {'name': 'Tom', 'age': 10}}}
表中的内容通常放在一起定义,不能定义两个同名的表。其实本质上带 .
的键名也是创建嵌套的表,会将最后一个点之前的名称作为表名,并创建对应的表,最后一个键作为属性值。例如
toml
table.person.chinese.fujian = '123'
会创建三个表,table
表里面包含 person
表,person
表里面包含 chinese
表
表的内容也可以写在同一行中,即内联表,将所有内容以一种紧凑的形式展现,类似于 json
toml
[table]
person = {name='Tom', age=19}
python
{'table': {'person': {'name': 'Tom', 'age': 19}}}
内联表也可以作为数组中的元素
toml
human = [{name='Tom', age=11}, {name='Sam', age=20}]
python
{'human': [{'name': 'Tom', 'age': 11}, {'name': 'Sam', 'age': 20}]}
表数组
顾名思义,即由表组合起来的数组,使用双方括号里面加表名的方式声明下面的表内容将作为数组中的一个元素,其中表名将作为数组的键,例如
toml
[[table]]
name = 'T1'
[[table.subtable]]
name = 'ST1'
[[table.subtable]]
name = 'ST2'
[[table]]
name = 'T2'
被解析为
python
{'table': [
{'name': 'T1', 'subtable': [
{'name': 'ST1'}, {'name': 'ST2'}
]},
{'name': 'T2'}]
}
R 解析文件
我们前面使用的 configr
包只能读取 toml
文件,而无法写入,所以我们使用另一个包 blogdown
,首先对包进行安装
r
install.packages('blogdown') # 1.13
blogdown::install_hugo()
安装成功后,读取 demo.toml
文件
toml
[table.person]
name = "Tom"
age = 10
直接使用包名加两个冒号来访问包内的函数,可以不用导入包,
r
blogdown::read_toml("demo.toml")
# $table
# $table$person
# $table$person$age
# [1] 10
#
# $table$person$name
# [1] "Tom"
将数据写入到文件中
r
data <- list(
name = 'Tom',
age = 30,
hobby = c('football', 'TV')
)
blogdown::write_toml(data, "dump.toml")
Python 解析文件
在 Python
中用于解析 toml
文件的包比较多,如 toml
、rtoml
、qtoml
、tomli
、tomlkit
等,由于 Python 3.11
标准库中加入的 tomllib
包是从 tomli
包而来,所以我们使用 tomli
包来解析 toml
文件,保持兼容
安装包
bash
pip install tomli # version 2.0.1
解析文件,需要以二进制的方式打开文件
python
import tomli
tomli.load(open('demo.toml', 'rb'))
# {'table': {'person': {'name': 'Tom', 'age': 10}}}
tomli
是一个只读取并解析文件的包,若要将数据写入到 toml
文件中,需要用到其对应的写入数据的版本 tomli_w
bash
pip install tomli-w # version 1.0.0
写入文件中
python
import tomli_w
data = {
'name': 'Tom',
'age': 30,
'hobby': ['football', 'TV']
}
tomli_w.dump(data, open('dump.toml', 'wb'))