2026年2月

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;