TOML Parser for Delphi
Delphi 没有支持 toml 格式解析的单元,从 github 上找到了来自悉尼的 Iwan Kelaiah 写的一个 TOML Parser for Free Pascal 单元。简单修改了一下,让其支持 delphi。
2025年5月,作者更新版本后已经可以支持表数组和内联表数组了。
2026年1月30日,修复表数组解析异常的问题。
原代码貌似只支持打开无签名的 utf-8 格式文件。为确保兼容性,修改为 ParseTOMLFile 函数可以打开常见编码格式的文件,如果没有签名则默认为 utf-8 格式。SerializeTOMLToFile 函数修改为支持签名和无签名两种 utf-8 格式(默认为有签名),兼容原始版本,即在函数的输入参数最后增加了一个默认值为 True 的 BOM 参数,来决定保存的文件有没有签名。
2026年2月26日。有感于读写方式过于繁琐,设计了一个辅助单元 TOML.Helper.pas,增加了大量方法来简化使用。
下载:TOML.rar
新增加的用法:
读取:
// 从文件加载 Config := NewTable.LoadFromFile('config.toml'); // 或: Config := LoadToml('config.toml'); // 基本类型 Config.GetStr(Key, Default); // 字符串 Config.GetInt(Key, Default); // 整数 Config.GetFloat(Key, Default); // 浮点数 Config.GetBool(Key, Default); // 布尔值 Config.GetDateTime(Key, Default); // 日期时间 // 复杂类型 Config.GetArray(Key); // 数组(返回nil表示不存在) Config.GetTable(Key); // 表(返回nil表示不存在) // 数组方法 Array.GetStr(Index, Default); Array.GetInt(Index, Default); Array.GetTable(Index); Array.ForEachTable(Procedure);写入:
// Set类 Config.SetStr('title', 'My App'); Config.SetInt('width', 1920); Config.SetFloat('scale', 1.5); Config.SetBool('debug', False); Config.SetDateTime('created', Now); Config.SetArray('tags', Tags); Config.SetTable('server', Server); // Put方法,支持重载,自动识别类型 Config := NewTable .Put('width', 1920) // 自动识别为 Integer .Put('height', 1080) .Put('title', 'My App') // 自动识别为 String .Put('debug', False); // 自动识别为 Boolean // 数组的 Add 方法 Tags := NewArray .AddStr('pascal') .AddStr('delphi') .AddStr('toml'); Ports := NewArray .AddInt(8080) .AddInt(8081) .AddInt(8082); // 更新或创建 Config.AddOrSetInt('port', 8080); Config.AddOrSetFloat('version', 1.3); Config.AddOrSetStr('title', 'Updated Title'); Config.AddOrSetBool('enabled', true); Config.AddOrSetDateTime('date',now); Config.AddOrSetArray('tags',tags); Config.AddOrSetTable('server', Server); // 创建表或数组 Config := NewTable; Tags := NewArray; // 或更短的别名 Config := Table; Tags := Arr; // 其它工具方法 Config.ToString; // 转换为字符串 Config.Count; // 获取键数量 Config.HasKey(Key); // 检查键是否存在 Config.GetKeys(List, Recursive); // 获取所有键名 Config.REmove('key'); // 删除键 Array.RemoveAt(idx); // 按索引删除数组中数据 Array.Clear; // 清空数组 Array.AddArray(NestedArray); // 嵌套数组示例:
//打开 toml 文件 Config := NewTable.LoadFromFile('config.toml'); // 或: Config := LoadToml('config.toml'); // 读取 width := Config.GetInt('width', 800); title := Config.GetStr('title'); debug := Config.GetBool('debug',False); name := Config.GetStr('server.host', 'localhost'); // 支持点分隔路径 //创建 Config := NewTable; Tags := NewArray; //创建同时赋值: Config := NewTable .SetStr('app_name', 'My Application') .SetStr('version', '1.0.0') .SetInt('port', 8080) .SetBool('debug', False); Tags := NewArray .AddStr('pascal') .AddStr('delphi') .AddStr('toml'); //创建嵌套结构: Config := NewTable .Put('server', NewTable .Put('host', 'localhost') .Put('port', 8080) ) .Put('database', NewTable .Put('host', 'localhost') .Put('port', 5432) .Put('pool_size', 10) ); // 写入 Config.SetStr('title', 'My App'); Config.SetInt('width', 1920); Config.SetBool('debug', False); // 自动识别类型写入 Config.Put('width', 1920) .Put('height', 1080) .Put('title', 'My App'); // 保存文件 Config.SaveToFile('config.toml'); //创建表数组 Servers := NewArray .AddTable( NewTable .Put('name', 'web-01') .Put('ip', '192.168.1.10') ) .AddTable( NewTable .Put('name', 'db-01') .Put('ip', '192.168.1.20') ); Config.SetArray('servers', Servers); // 遍历数组方式一 parameters.ForEachTable( procedure(param: TTOMLTable) begin showmessage(param.GetStr('name')); end ); // 遍历数组方式二 procedure ProcessParameter(param: TTOMLTable); begin showmessage(param.GetStr('name')); end; parameters.ForEachTable(ProcessParameter); // 调用
以下内容为翻译的一些原始用法:
config.toml 示例:
# 注释:config.toml
revision = "1.2.1af"
[project]
name = "My Amazing Project"
version = "1.0.0"
基本用法
- 读取 TOML 文件
program BasicParseTOML;
uses
TOML;
var
Config: TTOMLTable;
RevisionValue, ProjectValue, ProjectName: TTOMLValue;
ProjectTable: TTOMLTable;
begin
// 打开 TOML 文件
Config := ParseTOMLFromFile('config.toml');
try
// 访问字符串类型数据
if (Config.TryGetValue('revision', RevisionValue)) then
WriteLn('''revision'' 的值为:', RevisionValue.AsString);
// 安全地访问数据
if Config.TryGetValue('project', ProjectValue) and
(ProjectValue is TTOMLTable) then
begin
ProjectTable := TTOMLTable(ProjectValue);
if ProjectTable.TryGetValue('name', ProjectName) then
WriteLn('Project Name: ', ProjectName.AsString)
else
WriteLn('Project name 未找到。');
end
else
WriteLn('Project 配置未找到。');
finally
Config.Free;
end;
end.- 写入 TOML 文件
program BasicSerializeTOML;
uses
TOML;
var
Config: TTOMLTable;
Database: TTOMLTable;
begin
Config := TOMLTable;
try
Database := TOMLTable;
// 添加数据
Database.Add('host', TOMLString('localhost'));
Database.Add('port', TOMLInteger(5432));
// 修改数据
Database.Items.AddOrSetValue('enable',TOMLBoolean(True));
Config.Add('database', Database);
if SerializeTOMLToFile(Config, 'config.toml') then
WriteLn('配置保存成功。')
else
WriteLn('保存配置出错。');
finally
Config.Free;
end;
end.常见用法
- 使用数组
var
Config: TTOMLTable;
Tags: TTOMLArray;
begin
Config := TOMLTable;
try
Tags := TOMLArray;
Tags.Add(TOMLString('pascal'));
Tags.Add(TOMLString('toml'));
Config.Add('tags', Tags);
WriteLn(SerializeTOML(Config));
finally
Config.Free;
end;
end.- 嵌套表
var
Config: TTOMLTable;
Database: TTOMLTable;
begin
Config := TOMLTable;
try
Database := TOMLTable;
Database.Add('host', TOMLString('localhost'));
Database.Add('port', TOMLInteger(5432));
Config.Add('database', Database);
WriteLn(SerializeTOML(Config));
finally
Config.Free;
end;
end.- 序列化复杂结构
program BasicSerializeTOML;
uses
TOML, SysUtils;
var
Config, ServerConfig: TTOMLTable;
Ports: TTOMLArray;
SerializedTOML: string;
begin
Config := TOMLTable;
try
// 创建嵌套表
ServerConfig := TOMLTable;
ServerConfig.Add('host', TOMLString('127.0.0.1'));
ServerConfig.Add('enabled', TOMLBoolean(True));
// 创建和填充数组
Ports := TOMLArray;
Ports.Add(TOMLInteger(80));
Ports.Add(TOMLInteger(443));
ServerConfig.Add('ports', Ports);
// 添加 server 配置到主配置
Config.Add('server', ServerConfig);
// 添加一些基础元数据
Config.Add('version', TOMLFloat(1.0));
Config.Add('last_updated', TOMLDateTime(Now));
// 序列化为 TOML 格式
SerializedTOML := SerializeTOML(Config);
WriteLn('生成 TOML:');
WriteLn(SerializedTOML);
// 保存文件
if SerializeTOMLToFile(Config, 'config.toml') then
WriteLn('保存成功。');
finally
Config.Free;
end;
end.上述代码将生成 TOML 文件,内容如下:
version = 1.0
last_updated = 2024-03-20T15:30:45Z
[server]
host = "127.0.0.1"
enabled = true
ports = [ 80, 443 ]说明:所有数据都经过适当的类型检查和内存管理。该单元可确保:
- 每个值都有正确的 TOML 类型
- 数组保持类型一致性
- 所有对象都已正确释放
- 验证类型转换
- 内存管理
注意:
- 仅释放顶级 owner 表以避免内存管理问题。
- 适当的内存管理对于防止应用程序中的内存泄漏至关重要。
创建/释放表:
var
Config: TTOMLTable;
Database: TTOMLTable;
begin
Config := TOMLTable;
Database := TOMLTable;
//使用 Add 方法将嵌套表或值插入父表中。
Config.Add('database', Database);
// ... 添加其它嵌套表及数据...
Config.Free; // 仅释放顶级所有者即可自动释放所有嵌套的表和值。
end.避免显式释放嵌套对象:
• 不要手动释放嵌套表或值,以防止出现内存管理问题。
API 参考
类型
- TTOMLValue - 所有 TOML 值的基本类型
- TTOMLTable - TOML 表
- TTOMLArray - TOML 数组
- TTOMLString - TOML 字符串类型
- TTOMLInteger - TOML 整数类型
- TTOMLFloat - TOML 浮点类型
- TTOMLBoolean - TOML 布尔类型
- TTOMLDateTime - TOML 日期时间类型
用于创建 TOML 值的辅助函数
创建 TOML 字符串值。
TOMLString
function TOMLString(const AValue: string): TTOMLString;创建 TOML 整数值。
TOMLInteger
function TOMLInteger(const AValue: Int64): TTOMLInteger;创建 TOML 浮点值。
TOMLFloat
function TOMLFloat(const AValue: Double): TTOMLFloat;创建 TOML 布尔值。
TOMLBoolean
function TOMLBoolean(const AValue: Boolean): TTOMLBoolean;创建 TOML 时间日期格式。
TOMLDateTime
function TOMLDateTime(const AValue: TDateTime): TTOMLDateTime;创建 TOML 数组。
TOMLArray
function TOMLArray: TTOMLArray;创建 TOML 表。
TOMLTable
function TOMLTable: TTOMLTable;解析函数
- ParseTOML
将 TOML 格式的字符串解析为 TTOMLTable 对象。
function ParseTOML(const ATOML: string): TTOMLTable;
begin
Result := TOML.Parser.ParseTOMLString(ATOML);
end;• ParseTOMLFromFile
将 TOML 文件解析为 TTOMLTable 对象。
function ParseTOMLFromFile(const AFileName: string): TTOMLTable;
var
FileStream: TFileStream;
StringStream: TStringStream;
begin
FileStream := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
try
StringStream := TStringStream.Create('');
try
StringStream.CopyFrom(FileStream, 0);
Result := ParseTOMLString(StringStream.DataString);
finally
StringStream.Free;
end;
finally
FileStream.Free;
end;
end;序列化函数
SerializeTOML
将 TTOMLValue 序列化为 TOML 格式的字符串。function SerializeTOML(const AValue: TTOMLValue): string; begin Result := TOML.Serializer.SerializeTOML(AValue); end;
• SerializeTOMLToFile
序列化 TTOMLValue 并将其保存为文件(BOM:是否为带签名的 UTF-8 编码格式,默认有签名)。
function SerializeTOMLToFile(const AValue: TTOMLValue; const AFileName: string; BOM: Boolean = True): Boolean;
begin
Result := TOML.Serializer.SerializeTOMLToFile(AValue, AFileName; BOM: Boolean = True);
end;