什么是 TOML?零基础也能看懂的配置文件格式入门指南
一、TOML 是什么?一句话讲清楚
TOML,全称 Tom's Obvious, Minimal Language(汤姆的明显最小化语言),由 GitHub 联合创始人 Tom Preston-Werner 于 2013 年创建。它的设计目标只有一个:让配置文件既能被人轻松读懂,又能被机器精确解析,且无歧义地映射为哈希表。
你可以把它理解为一种"升级版的 INI 文件"——它保留了 INI 的简洁,却支持嵌套结构、数组、日期时间等复杂数据类型,同时比 JSON 多了注释功能,比 YAML 少了缩进带来的歧义。
TOML 已成为众多主流工具的首选配置格式:
Python 项目的
pyproject.toml(Poetry、Flit 等包管理工具)Rust 项目的
Cargo.toml(官方包管理配置)Hugo 静态网站生成器、GitHub Actions 工作流等
二、为什么选择 TOML?三大核心优势
| 特性 | TOML | JSON | YAML |
|---|---|---|---|
| 支持注释 |
✅ 支持 # 注释 | ❌ 不支持 | ✅ 支持 |
| 语法简洁度 | 键值对,无多余符号 |
大量 {} [] "" | 缩进敏感,容易出错 |
| 数据类型丰富度 | 字符串/数字/布尔/日期/数组/表 | 仅6种基础类型 | 丰富但有歧义 |
| 人类可读性 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| 无歧义映射 | ✅ 严格映射哈希表 | ✅ | ⚠️ 缩进可能产生歧义 |
TOML 的三大核心优势:
直观易读:采用类 INI 文件的结构,语法简洁明了,非技术人员也能轻松理解
无歧义映射:严格的语法规则确保配置文件能唯一映射到哈希表结构,不会出现"同一份配置解析出不同结果"的情况
多语言支持:几乎所有主流编程语言都有成熟的 TOML 解析库(Python、Rust、Go、JavaScript 等)
三、TOML 基础语法:从键值对开始
TOML 文件的最基本构成单元是键值对(Key = Value),格式为 key = value。
name = "MyApp" version = "1.0.0" enabled = true
核心规则:
键和等号之间允许有空格,等号和值之间也允许有空格,空格会被忽略
键值对必须写在同一行,不能跨行
每个键值对后必须换行或结束文件
TOML 大小写敏感:
Name和name是两个不同的键
键名的三种形式
| 键名类型 | 示例 | 说明 |
|---|---|---|
| 裸键(Bare Key) | server_port = 8080 | 只能包含字母、数字、下划线、短横线 |
| 引号键(Quoted Key) | "server address" = "192.168.1.1" | 支持空格、特殊字符、中文 |
| 点分隔键(Dot Key) | physical.color = "orange" |
等价于 [physical] color = "orange" |
四、TOML 支持的数据类型(重点)
这是 TOML 最强大的地方——它原生支持丰富的数据类型,不像 JSON 那样一切都是字符串或数字。
1. 字符串:四种写法,应对所有场景
| 类型 | 语法 | 示例 | 适用场景 |
|---|---|---|---|
| 基本字符串 |
双引号 " | "Hello\nWorld" | 需要转义字符时 |
| 多行基本字符串 |
三个双引号 """ | """Line1\nLine2""" | 多行文本 |
| 字面量字符串 |
单引号 ' | 'C:\Users\Tom' | 路径、正则表达式(不转义) |
| 多行字面量字符串 |
三个单引号 ''' | '''多行代码''' | 代码块、脚本 |
关键区别:字面量字符串(单引号)不处理任何转义字符,所见即所得。 这对于写 Windows 路径极其友好:
# 推荐:字面量字符串,反斜杠不会被转义 path = 'C:\Users\Tom\Documents\file.txt' # 不推荐:基本字符串,需要双写反斜杠 path = "C:\\Users\\Tom\\Documents\\file.txt"
2. 数字:整数、浮点数、特殊值
integer = 42 # 整数 negative = -17 # 负数 float = 3.14159 # 浮点数 scientific = 1e6 # 科学计数法 = 1000000.0 hex = 0xDEADBEEF # 十六进制 octal = 0o755 # 八进制 binary = 0b11010110 # 二进制
支持下划线增强可读性: big_number = 1_000_000(等价于 1000000)
特殊浮点值(均为小写):
| 值 | 含义 |
|---|---|
inf / +inf / -inf | 正无穷 / 负无穷 |
nan / +nan / -nan | 非数字(Not a Number) |
3. 布尔值:只有两个值,必须小写
is_enabled = true debug_mode = false
注意:只能写 true 或 false,不能写 True、FALSE、1、0。TOML 对此非常严格。
4. 日期时间:原生支持,无需自己解析
| 类型 | 格式 | 示例 |
|---|---|---|
| 偏移日期时间(带时区) | RFC 3339 | 1979-05-27T07:32:00Z |
| 本地日期时间 | 无时区 | 1979-05-27T07:32:00 |
| 本地日期 | YYYY-MM-DD | 1979-05-27 |
| 本地时间 | HH:MM:SS | 07:32:00 |
5. 数组:方括号包裹,支持混合类型
colors = ["red", "yellow", "green"] numbers = [1, 2, 3, 4] mixed = [1, "two", true] # 混合类型数组 nested = [[1, 2], [3, 4, 5]] # 嵌套数组
数组可以跨多行书写,最后一个元素后的逗号可省略:
fruits = [ "apple", "banana", "cherry" # 逗号可选 ]

五、TOML 的核心数据结构:表与数组表
如果说键值对是 TOML 的"原子",那么"表(Table)"就是 TOML 的"分子"。
1. 表(Table):用方括号定义,相当于"命名空间"
[database] host = "localhost" port = 5432 enabled = true
这等价于 JSON 中的:{"database": {"host": "localhost", "port": 5432, "enabled": true}}
2. 嵌套表:两种写法
# 方式1:点分隔(推荐) [server.alpha] ip = "10.0.0.1" role = "frontend" # 方式2:逐层定义 [server] [server.beta] ip = "10.0.0.2" role = "backend"
3. 内联表:一行写完,适合简单结构
# 等价于上面的 [server.alpha] 定义
server = { ip = "10.0.0.1", role = "frontend" }4. 数组表(Array of Tables):TOML 的杀手级特性 ⭐
当你需要配置多个同结构的对象时(比如多台服务器、多个用户),数组表是最佳选择。
[[servers]] name = "Server1" ip = "192.168.1.1" port = 8080 [[servers]] name = "Server2" ip = "192.168.1.2" port = 8081
这等价于 JSON 中的:
{"servers": [{"name": "Server1", "ip": "192.168.1.1", "port": 8080}, {"name": "Server2", "ip": "192.168.1.2", "port": 8081}]}数组表是 TOML 相比 JSON 和 YAML 最大的优势之一——它能清晰表达"一组同类型配置项",且每个项可以有不同的键。
六、注释规则
TOML 只支持一种注释方式:# 从 # 开始到行尾的所有内容都是注释。
# 这是一个完整行的注释 name = "MyApp" # 这是行尾注释
注意:注释不能出现在字符串内部。
# 错误示例: bad = "这不是#注释,这是字符串内容" # 整个值是字符串,# 不是注释
七、完整示例:一个真实的 TOML 配置文件
# 项目元数据
title = "My Awesome App"
version = "1.0.0"
[database]
enabled = true
host = "localhost"
port = 5432
username = "app_user"
password = "secret"
# 内联表
connection_pool = { max_connections = 20, timeout_seconds = 30 }
# 数组
supported_types = ["postgresql", "mysql"]
[servers.alpha]
ip = "10.0.0.1"
role = "frontend"
[servers.beta]
ip = "10.0.0.2"
role = "backend"
# 数组表
[[users]]
id = 1
name = "Alice"
hobbies = ["reading", "hiking"]
[[users]]
id = 2
name = "Bob"
hobbies = ["gaming"]
[cache]
redis_url = "redis://localhost:6379"
ttl_minutes = 60八、Python 中如何读写 TOML
Python 3.11+:使用内置 tomllib(推荐)
Python 3.11 开始,标准库内置了 tomllib 模块,无需安装任何第三方库即可读取 TOML。
import tomllib
# 读取 TOML 文件(必须用 rb 模式打开)
with open("config.toml", "rb") as f:
config = tomllib.load(f)
print(config["database"]["host"]) # 输出: localhost
print(config["servers"][0]["ip"]) # 输出: 10.0.0.1从字符串解析:
import tomllib
toml_str = """
title = "从字符串加载"
count = 5
is_active = true
"""
data = tomllib.loads(toml_str)
print(data) # {'title': '从字符串加载', 'count': 5, 'is_active': True}数据类型自动转换对照表:
| TOML 类型 | Python 类型 | 示例 |
|---|---|---|
| string | str | "Hello" → "Hello" |
| integer | int | 42 → 42 |
| float | float | 3.14 → 3.14 |
| boolean | bool | true → True |
| date-time | datetime.datetime | 2024-01-01T12:00:00Z → datetime 对象 |
| array | list | [1, 2, 3] → [1, 2, 3] |
| table | dict | [section]\nkey = "val" → {"section": {"key": "val"}} |
| array of tables | list[dict] | [[sec]]\nkey = val → [{"sec": {"key": "val"}}] |
写入 TOML:Python 3.11+ 用 tomli-w
import tomli_w
config = {
"project": {"name": "new_app", "version": "2.0.0"},
"servers": [{"name": "server3", "ip": "192.168.1.3"}]
}
with open("new_config.toml", "w", encoding="utf-8") as f:
tomli_w.dump(config, f, indent=2) # indent 控制缩进
Python 3.10 及以下:使用第三方库 tomli + tomli-w
pip install tomli tomli-w
import tomli # 读取 import tomli_w # 写入
旧方案:使用 toml 库(第三方,功能完整但非标准库)
pip install toml
import toml
# 读取
config = toml.load("config.toml")
# 写入
toml.dump(config, open("output.toml", "w"))
# 字符串转换
toml_str = toml.dumps(config)
print(toml_str)九、TOML 最佳实践
键名使用小写字母,单词间用下划线或短横线分隔:
server_port或server-port,不要用serverPort表格命名使用有意义的名称,避免过深嵌套:
[database.connection.pool]可以,但[a.b.c.d.e]不推荐数组表保持一致的键结构:每个
[[users]]块最好有相同的字段路径使用字面量字符串(单引号):避免转义地狱
文件编码必须是 UTF-8:这是 TOML 规范的硬性要求
TOML 没有 null 类型:如需表示空值,用空字符串
""或直接省略该键
十、常见陷阱与注意事项
| 陷阱 | 说明 | 正确做法 |
|---|---|---|
| 布尔值大小写 | True、FALSE 都是错误的 |
只能用 true / false(全小写) |
| 键名大小写敏感 | Name 和 name 是不同的键 | 统一使用小写命名 |
| 不能重复定义同一键 | 后定义的会覆盖先定义的 | 避免重复,或使用数组表 |
| 注释不能在字符串内 | "# 不是注释" 整个是字符串 | 注释只能在键值对之外 |
| 浮点数 vs 整数 | 42 是整数,42.0 是浮点数 | TOML 严格区分,不会自动转换 |
| 日期时间精度 | 毫秒级是必须的,更高精度会被舍弃 | 按 RFC 3339 格式书写 |
十一、TOML 在真实项目中的应用
| 项目/工具 | TOML 文件 | 用途 |
|---|---|---|
| Python (Poetry) | pyproject.toml | 项目元数据、依赖管理、构建配置 |
| Rust (Cargo) | Cargo.toml | 包信息、依赖声明、功能开关 |
| Hugo | config.toml | 静态网站全局配置 |
| GitHub Actions | .github/workflows/*.yml(部分支持TOML) | CI/CD 工作流 |
| Deno | deno.json(TOML 格式) | 项目配置 |
一个典型的 pyproject.toml 示例:
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "my-package"
version = "1.0.0"
authors = [{name = "John Doe", email = "john@example.com"}]
dependencies = ["requests>=2.25.0"]
[project.optional-dependencies]
dev = ["pytest>=6.0", "black>=21.0"]十二、相关工具推荐
TOML转JSON工具:https://www.fuwa.org/tools/toml-to-json.html
JSON转TOML工具:https://www.fuwa.org/tools/json-to-toml.html
总结
TOML 的本质,是用最少的语法符号,表达最丰富的配置信息。 它不追求花哨,只追求一件事:让人一眼就能看懂,让机器一解析就不会出错。
从 key = value 的简单键值对,到 [[table]] 的数组表;从 'C:\path' 的字面量字符串,到 2024-01-01T12:00:00Z 的原生日期时间——TOML 把配置文件该有的能力,全部给齐了,而且给得优雅。
如果你正在为项目选配置文件格式,TOML 是一个不会后悔的选择。
相关工具
TOML转JSON工具
JSON转TOML工具
版权及免责申明:本文由@fuwa原创发布。该文章观点仅代表作者本人,不代表本站立场。本站不承担任何相关法律责任。
如若转载,请注明出处:https://www.fuwa.org/tutorials/what-is-toml.html

