toml11读,写,格式转换

前言

  1. 写这个文章的目的,还是因为在网上没有找到合适的资料,所以自己来写一个
  2. toml11简中的资料是在是太少.你去搜吧,能看的资料几乎没有.这也是我写这个文章的缘由.说白了还是用的人太少了.
  3. 官方的文档也是"过于简洁".只有github上的一个readme可以参考.资料太少就会导致你的开发周期被加长,时间被浪费.
  4. 你要是读文件还行, 也比较简单,但是一旦牵扯到格式转化,这个库也做不到,和我之前用的boost解析json确实有一些差距,所以我简单实现了一下.
  5. 比如toml中的布尔量,你定义一个a,a=false,这么写是可以;但是你,a=0;这种情况下,toml11却无法解析.这种情况下你给同事使用,无疑是增加了学习成本.
  6. 另外就是写数据到toml中,这个在toml11的文档中资料很少,简中一点都没搜到.我的文档中会对这个也有介绍.
  7. 针对上面所说的问题,这也是写这个文档的缘由.

官方资料

具体的还是看这个,怎么说这个是官方的资料

ToruNiina/toml11: TOML for Modern C++ (github.com)

读文件

toml::get_or

  toml::get_or 函数用于从 toml::value 对象中获取指定键的值。 如果键存在,则返回相应的值; 如果键不存在,则返回用户提供的默认值。

toml::get_or<double>(data, "a", 0.1) 
表示获取键为 "a" 的值,如果存在则返回对应的浮点数值,如果不存在则返回默认值 0.1。

需要注意的是,使用 toml::get_or 的前提是你能够确定配置项的类型,并且在键不存在时能够提供一个合适的默认值。

如果你无法确定类型或者默认值是无法确定的,可以使用其他处理方式,比如手动检查键是否存在 ,然后根据情况再使用 toml::find 或 toml::find_or。

toml::find_or

在 toml11 库中,toml::find_or 函数用于从 toml::value 对象中获取指定键的值。

toml::find_or<double>(data, "a", 0.1)
 表示获取键为 "a" 的值,如果存在则返回对应的浮点数值,如果不存在则返回默认值 0.1。

要注意的是:

toml文件中a=1.0,为浮点数。这么读肯定是没有问题的,toml::find_or<double>(data, "a", 0.1)

如果配置项不存在,就是默认值0.1如果配置项不是浮点数,他也是默认值。!!!这个要注意下

type

返回读取toml配置项的类型

auto valueType = toml::find(data, key).type();

find

在 toml11 中,toml::find 函数用于从 toml::value 对象中获取指定键的值。

template<typename T>
T find(const toml::value& v, const std::string& key);
不能指定默认参数

[fruit]
name = "apple"
[fruit.physical]
color = "red"
shape = "round"


const auto  data  = toml::parse("fruit.toml");
//当读取的不是具体条目的时候,不用指定类型
const auto& fruit = toml::find(data, "fruit");
//当读取的是具体条目的时候,需要指定类型——如果类型和toml中的类型不对的话,就会造成程序退出。内部是不会进行类型转换
const auto  name  = toml::find<std::string>(fruit, "name");

demo1

#include <toml.hpp>
#include <iostream>
#include <fstream>

int main() {
	// 创建一个 TOML 表
	toml::value data{
		{"title", "example"},
		{"owner", toml::value{
			{"name", "Tom Preston-Werner"},
			{"dob", "1979-05-27"}
		}},
		{"database", toml::value{
			{"server", "192.168.1.1"},
			{"ports", toml::array{8001, 8001, 8002}},
			{"connection_max", 5000},
			{"enabled", true}
		}}
	};

	// 将 TOML 表写入文件
	std::ofstream ofs("example.toml");
	ofs << data;

	// 检查写入是否成功
	if (ofs.good()) {
		std::cout << "Data successfully written to example.toml" << std::endl;
	}
	else {
		std::cerr << "Error writing to example.toml" << std::endl;
	}

	return 0;
}

结果

title = "example"

[owner]
name = "Tom Preston-Werner"
dob = "1979-05-27"

[database]
server = "192.168.1.1"
ports = [
8001,
8001,
8002,
]
connection_max = 5000
enabled = true

demo2

void writeToml()
{
	// 创建一个 TOML 文档
	toml::value doc;

	// 添加一些键值对、数组和表
	doc["key1"] = 42;           // 整数
	doc["key2"] = 3.14;         // 浮点数
	doc["key3"] = "hello";      // 字符串

	toml::array arr;
	arr.push_back(1);
	arr.push_back(2);
	doc["my_array"] = arr;      // 数组

	toml::value nested_table;
	nested_table["nested_key"] = "world";
	doc["nested"] = nested_table; // 表

	// 将文档输出为 TOML 字符串
	std::string toml_str = toml::format(doc);

	// 将 TOML 字符串写入文件
	std::ofstream file("./example.toml");
	file << toml_str;
	file.close();

	return;
}

结果

key1 = 42
key2 = 3.1400000000000001
key3 = "hello"
my_array = [1,2]
nested = {nested_key="world"}

多层嵌套

这个真是麻烦,而且也找不到资料,官方文档里也没怎么写。

我当时写的时候也是非常费劲,我这边是双层map遍历,牵扯到读,写,修改,以及判断某些配置项是否存在,并且和map同步确实有点复杂。

我就两个建议,如果你不是非toml必选,我建议你换。toml是很好,toml11我觉得还是差点。

另外就是问AI,但根据我的经验来看,你问大概率也是不对的,需要花一段改。这本质上还是因为toml11的资料少,投喂AI训练也不够。

格式转化

编译器最低支持C++17,才能编译.

支持默认值.支持类型转换,

使用方法:

配置文件

a="1"
b=0;
#c未在配置文件中

demo

//data:toml的toml::value key:toml的中配置项 default_value:该配置项的默认值
GetTomlValue(const toml::value &data, const std::string &key, const T &default_value)

int a= GetTomlValue<int>(data, "a", 200);//a在toml中是字符,这里转换成int类型读出来
bool b = GetTomlValue<bool>(data, "b", false);//b在toml中是是整形,这里转换成bool类型读出来
float c = GetTomlValue<bool>(data, "c",1.1);//c在toml中不存在,这里给c赋值默认值1.1

源码:

template <typename T>
T GetTomlValue(const toml::value &data, const std::string &key)
{
	if (!(is_same_v<T, string> || is_same_v<T, int> || is_same_v<T, unsigned int> || is_same_v<T, unsigned long long> || is_same_v<T, float> || is_same_v<T, bool>))
	{
		LogError("Toml文件函数模板,目前只处理了string,int,unsigned int,unsigned long long,float,bool这四个常用类型。其他类型手动添加下即可");
		exit(-1);
	}
	auto valueType = toml::find(data, key).type();
	switch (valueType)
	{
	case toml::value_t::integer:
	{
		unsigned long long value = toml::find<unsigned long long>(data, key);
		if constexpr (is_same_v<std::decay_t<T>, int> || is_same_v<T, unsigned int> || is_same_v<T, unsigned long long> || is_same_v<T, float> || is_same_v<T, bool>)
			return value;
		else {
			LogError(key + "TOML文件类型转化,不支持从int转化到" + (string) typeid(T).name());
			exit(-1);
		}
	}
	break;
	case toml::value_t::floating:
	{
		float value = toml::find<float>(data, key);
		if constexpr (std::is_same_v<std::decay_t<T>, float>) // 想要的是float
			return value;
		else if constexpr (std::is_same_v<std::decay_t<T>, int>) // 想要的是int
			return static_cast<int>(value);
		else {
			LogError(key + "TOML文件类型转化,不支持从float转化到" + (string) typeid(T).name());
			exit(-1);
		}
	}
	break;
	case toml::value_t::string:
	{
		string value = toml::find<string>(data, key);
		if constexpr (std::is_same_v<std::decay_t<T>, string>) // 想要的是string
			return value;
		else if constexpr (std::is_same_v<std::decay_t<T>, int>)
			return stoi(value);
		else if constexpr (std::is_same_v<std::decay_t<T>, unsigned int>)
			return stoul(value);
		else if constexpr (std::is_same_v<std::decay_t<T>, unsigned long long>)
			return stoull(value);
		else if constexpr (std::is_same_v<std::decay_t<T>, float>)
			return stof(value.c_str());
		else if constexpr (std::is_same_v<std::decay_t<T>, bool>)
		{
			if (value == "1" || value == "0")
				return atoi(value.c_str());
			else if (value == "true")
				return 1;
			else if (value == "false")
				return 0;
			else
			{
				LogError("Toml文件配置项,布尔量" + key + "=" + value + ",应该在0,1或true,false选择");
				exit(-1);
			}
		}
		else {
			LogError(key + "TOML文件类型转化,不支持从string转化到" + (string) typeid(T).name());
			exit(-1);
		}
		break;
	}
	case toml::value_t::boolean:
	{
		if constexpr (std::is_same_v<std::decay_t<T>, bool>)
			return toml::find<bool>(data, key);
		else {
			LogError(key + "TOML文件类型转化,不支持从bool转化到" + (string) typeid(T).name());
			exit(-1);
		}
	}
	break;
	// 其他类型的处理
	default:
		LogError("TOML文件类型转化,我做的GetTomlValue函数模板,不支持这个类型,可以尝试练习我做个适配!");
		exit(-1);
		break;
	}
	return 0;
}

template <typename T>
T GetTomlValue(const toml::value &data, const std::string &key, const T &default_value)
{
	return data.contains(key) ? GetTomlValue<T>(data, key) : default_value;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值