最近在项目中需要对Yaml文件进行读取,我是做c#的,一般用到的是XML,JSON,INI做配置文件,合作的人是做python的,非要让我读Yaml文件,我这个做小兵的虽然很不服气,但是自己之前也没做这c#读取Yaml文件的操作,刚好乘这个机会学习一下。
写在前面
用到的技术与版本
项目框架:Windows 窗体应用(.NET Framework 4.8.1)
Newtonsoft.Json包 13.0.3
Yamldotnet包 16.1.0
系统版本:Windows 11 专业版
准备工作
Yaml数据在C#中进行定义
在对Yaml文件进行读取前,先将Yaml文件中的数据结构在c#中进行定义,以便后面更好的读取。
这里对这四个类型进行举例(这里为了想看看这四个类型到Yaml文件的格式是什么样子的)
- 右击项目选择添加->新建项
- 命名一个类名,这里以 YamlClass.cs为例
- 添加以下代码
internal class YamlClass
{
public string[] arraytest { get; set; }
public string stringtest { get; set; }
public int inttest { get; set; }
public Dictionary<string, string> dictionarytest { get; set; }
}
对Yaml文件的读取与写入代码的添加
数据准备好后,需要添加对Yaml文件操作。
- 右击项目,选择“管理NuGet程序包”
- 搜索YamlDotNet,进行下载
- 下载完成后,右击项目选择添加->新建项,命名一个类名,这里以 YamlHelper.cs为例,这里放对Yaml文件的读取操作代码
写入数据到Yaml文件的代码:
public static bool WriteToYaml<T>(string file, T obj)
{
return SerializeToFile(file, obj);
}
public static string Serialize<T>(T target)
{
var _serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build();
return _serializer.Serialize(target);
}
public static bool SerializeToFile<T>(string filePath, T target)
{
var content = Serialize(target);
File.WriteAllText(filePath, content, Encoding.UTF8);
return true;
}
读取Yaml文件数据的代码:
public static T ReadYaml<T>(string file)
{
var target = DeserializeFromFile<T>(file);
return target;
}
public static T Deserialize<T>(string yaml)
{
IDeserializer _deserializer = new DeserializerBuilder().WithNamingConvention(UnderscoredNamingConvention.Instance).Build();
return _deserializer.Deserialize<T>(yaml);
}
public static T DeserializeFromFile<T>(string filePath)
{
var yaml = File.ReadAllText(filePath, Encoding.UTF8);
return Deserialize<T>(yaml);
}
将这两段代码写到YamlHelper.cs文件中
至此准备工作完成。
窗体控件控制操作
准备工作做好后,就可以调用方法进行对Yaml文件的写入和读取了。
这里放了两个按钮来控制操作,一个TextBox进行显示。
写入数据到Yaml文件
双击“写入数据到Yaml文件”按钮进入clik事件。
添加以下代码:
private void button_write_yaml_Click(object sender, EventArgs e)
{
var test = new YamlClass();
test.arraytest = new string[] { "ABC1", "BCD", "123" };
test.stringtest = "这是测试";
test.inttest = 5;
test.dictionarytest = new Dictionary<string, string>();
test.dictionarytest.Add("KEY1", "VAL1");
test.dictionarytest.Add("KEY2", "VAL2");
test.dictionarytest.Add("KEY3", "VAL3");
YamlHelper.WriteToYaml<YamlClass>("test.yaml", test);
}
运行一下。
此时数据已经写入到Yaml文件中了。
文件路径为:WorkDemo\WorkDemo\bin\Debug
文件内容:
读取Yaml文件数据
双击“读取Yaml文件数据到代码”按钮进入clik事件。
添加以下代码:
private void button_read_yaml_Click(object sender, EventArgs e)
{
var test = YamlHelper.ReadYaml<YamlClass>("test.yaml");
textBox_display.Text = string.Empty;
textBox_display.Text += (String.Join(",", test.arraytest));
textBox_display.AppendText(System.Environment.NewLine);
textBox_display.Text += test.stringtest.ToString();
textBox_display.AppendText(System.Environment.NewLine);
textBox_display.Text += test.inttest.ToString();
textBox_display.AppendText(System.Environment.NewLine);
textBox_display.Text += test.dictionarytest.Count;
textBox_display.AppendText(System.Environment.NewLine);
}
运行一下,点击“读取Yaml文件数据到代码”按钮,Yaml内容出现。
Yaml数据转换成json
上述已经将yaml数据读取出来了,接下来只需要对读取到的yaml数据进行转换就可以了。
首先先添加一个包。
右击项目选择“管理NuGet程序包”,搜索Newtonsoft.Json,并下载。
这里我新添加了一个name为“button_yaml_to_json_Click”按钮来做这个事情 。
private void button_yaml_to_json_Click(object sender, EventArgs e)
{
if (yamlData == null)
{
MessageBox.Show("yaml 数据为空。");
return;
}
var serializer = new JsonSerializer();
serializer.Formatting = Newtonsoft.Json.Formatting.Indented; // For pretty-printed JSON
using (var stringWriter = new StringWriter())
{
serializer.Serialize(stringWriter, yamlData);
// 解析 JSON 字符串
var jsonData = JsonConvert.DeserializeObject<YamlClass>(stringWriter.ToString());
// 获取某一个关键字的值
Console.WriteLine(jsonData.stringtest);
}
}
主要的语句在
var jsonData = JsonConvert.DeserializeObject<YamlClass>(stringWriter.ToString());
其中YamlClass为之前定义的yaml数据类。
改进——对yaml文件读取时根据yaml文件中的键进行获取,对c#中怎么取名字无关
上述对yaml文件进行读取时,yaml文件中的key是什么样子的,c#中也要定义成什么样子。
比如:
在yaml中,key为arraytest时,在c#中定义类时也要命名为arraytest。
下面的方法可以将这两个分开,yaml文件中怎么命名与c#中怎么命名无关。
只需要在定义类的地方添加一行
[YamlMember(Alias = “yaml文件中key的值”)]
[YamlMember(Alias = "arraytest")]
public string[] arraytest { get; set; }
[YamlMember(Alias = "stringtest")]
public string stringtest { get; set; }
[YamlMember(Alias = "inttest")]
public int inttest { get; set; }
[YamlMember(Alias = "dictionarytest")]
public Dictionary<string, string> dictionarytest { get; set; }
我这里是凑巧yaml文件中有key值和我自己定义的属性名一致了,实际上只要双引号中的字符串与yaml文件中的key一致就可以。
yaml文件中多个数据读取
以本文中arraytest,stringtest,inttest,dictionarytest四个元素为列,当我在yaml文件中保存多个这样的数据该如何读写呢。
这里只需要改变定义的类。
原本:
internal class YamlClass
{
public string[] arraytest { get; set; }
public string stringtest { get; set; }
public int inttest { get; set; }
public Dictionary<string, string> dictionarytest { get; set; }
}
这样存储到yaml文件中的格式为:
现在:
internal class YamlClass
{
public class YamlClassCell
{
public string[] arraytest { get; set; }
public string stringtest { get; set; }
public int inttest { get; set; }
public Dictionary<string, string> dictionarytest { get; set; }
}
public List<YamlClassCell> yamlClass { get; set; }
}
这样存储到yaml文件中的格式为:
遇到的问题
有一个地方很奇怪,如果将yaml文件中数据的内容比喻成[key:value],当key中单词有大写时,则在c#中用这样的方式读取是不成功的。
我搜索了这样的问题还是没有得到解决。
所以我把YamlClass.cs中的属性名全部改成了小写,这样写入到Yaml文件的时候key也会成为小写,避免了这样的问题。
有大佬知道原因吗?qAq
总结的小点
- 在用[YamlMember(Alias = “yaml文件中key的值”)]这样的方法进行写操作时,当"yaml文件中key的值"中用到“_小写”时,写到yaml文件中的会变成“大写”,比如在c#中代码为[YamlMember(Alias = “yaml_class”)],写到yaml文件中就为
- TBD
参考的文章
https://blog.csdn.net/fengershishe/article/details/139362271
https://www.cnblogs.com/hnzhengfy/p/yaml_CS_example.html