using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using Masuit.Tools.Reflection; namespace Masuit.Tools.Files; /// /// INI文件操作辅助类 /// public class IniFile { private readonly Dictionary _sections; private readonly StringComparer _stringComparer; private readonly BoolOptions _boolOptions; private readonly string _path; /// /// 全局配置节 /// public const string DefaultSectionName = "General"; /// /// /// /// 文件路径 /// /// public IniFile(string path, StringComparer comparer = null, BoolOptions boolOptions = null) { _path = path; _stringComparer = comparer ?? StringComparer.CurrentCultureIgnoreCase; _sections = new Dictionary(_stringComparer ?? StringComparer.CurrentCultureIgnoreCase); _boolOptions = boolOptions ?? new BoolOptions(); if (File.Exists(path)) { using StreamReader reader = new(path, Encoding.UTF8); IniSection section = null; while (reader.ReadLine() is { } line) { ParseLine(line, ref section); } } } /// /// 重新加载文件 /// public void Reload() { _sections.Clear(); using StreamReader reader = new(_path, Encoding.UTF8); IniSection section = null; while (reader.ReadLine() is { } line) { ParseLine(line, ref section); } } private void ParseLine(string line, ref IniSection section) { if (string.IsNullOrWhiteSpace(line)) { return; } line = line.Trim(); if (line[0] == ';') { return; } if (line[0] == '[') { var name = line.Trim('[', ']').Trim(); if (name.Length > 0 && !_sections.TryGetValue(name, out section)) { section = new IniSection(name, _stringComparer); _sections.Add(section.Name, section); } } else { string name, value; var strs = line.Split(';')[0].Split('='); if (strs.Length == 1) { name = line.Trim(); value = string.Empty; } else { name = strs[0].Trim(); value = strs.Skip(1).Join("=").Trim(); } if (name.Length <= 0) { return; } if (section == null) { section = new IniSection(DefaultSectionName, _stringComparer); _sections.Add(section.Name, section); } if (section.TryGetValue(name, out var item)) { item.Value = value; } else { item = new IniItem { Name = name, Value = value }; section.Add(name, item); } } } /// /// 保存配置文件 /// public void Save() { using StreamWriter writer = new(_path, false, Encoding.UTF8); bool firstLine = true; foreach (var section in _sections.Values.Where(section => section.Count > 0)) { if (firstLine) { firstLine = false; } else { writer.WriteLine(); } writer.WriteLine($"[{section.Name}]"); foreach (var setting in section.Values) { writer.WriteLine(setting.ToString()); } } } /// /// 异步保存配置文件 /// /// public async Task SaveAsync() { using StreamWriter writer = new(_path, false, Encoding.UTF8); var firstLine = true; foreach (var section in _sections.Values.Where(section => section.Count > 0)) { if (firstLine) { firstLine = false; } else { await writer.WriteLineAsync(); } await writer.WriteLineAsync($"[{section.Name}]"); foreach (var setting in section.Values) { await writer.WriteLineAsync(setting.ToString()); } } } #region Read values /// /// 获取指定节的指定键的值 /// /// 节 /// 键 /// 获取不到时的默认值 /// /// public string GetValue(string section, string key, string defaultValue = null) { if (section == null) { throw new ArgumentNullException(nameof(section)); } if (key == null) { throw new ArgumentNullException(nameof(key)); } if (!_sections.TryGetValue(section, out var iniSection)) { return defaultValue; } if (iniSection.TryGetValue(key, out var iniSetting)) { return iniSetting.Value; } return defaultValue; } /// /// 获取指定节的指定键的值 /// /// /// 配置节 /// 键 /// 获取不到时的默认值 /// public T GetValue(string section, string key, T defaultValue = default) where T : IConvertible { return GetValue(section, key).TryConvertTo(defaultValue); } /// /// 所有的配置节 /// /// public List GetSections() => _sections.Values.ToList(); /// /// 获取指定节的所有键值对 /// /// 节 /// /// public Dictionary GetSection(string section = DefaultSectionName) { if (section == null) { throw new ArgumentNullException(nameof(section)); } var values = _sections.TryGetValue(section, out var iniSection) ? iniSection.Values : Enumerable.Empty(); return values.ToDictionary(x => x.Name, x => x.Value); } /// /// 获取指定节的配置并绑定到指定类型 /// /// /// 节 /// public T GetSection(string section = DefaultSectionName) where T : class, new() { var dic = GetSection(section); var obj = new T(); var properties = typeof(T).GetProperties().ToDictionary(p => p.GetAttribute()?.Name ?? p.Name); foreach (var item in dic.Where(item => properties.ContainsKey(item.Key))) { properties[item.Key].SetValue(obj, item.Value.ConvertTo(properties[item.Key].PropertyType)); } return obj; } #endregion Read values #region Write values /// /// 设置指定节的指定键的值 /// /// 节 /// 键 /// 值 /// public void SetValue(string section, string key, string value) { if (section == null) { throw new ArgumentNullException(nameof(section)); } if (key == null) { throw new ArgumentNullException(nameof(key)); } if (!_sections.TryGetValue(section, out var sec)) { sec = new IniSection(section, _stringComparer); _sections.Add(sec.Name, sec); } if (!sec.TryGetValue(key, out var item)) { item = new IniItem { Name = key }; sec.Add(key, item); } item.Value = value ?? string.Empty; } /// /// 设置指定节的指定键的值 /// /// 节 /// 键 /// 值 public void SetValue(string section, string key, bool value) => SetValue(section, key, _boolOptions.ToString(value)); /// /// 设置指定节的指定键的值 /// /// 节 /// 键 /// 值 public void SetValue(string section, string key, T value) where T : IConvertible => SetValue(section, key, value.ToString()); /// /// 清空配置节 /// /// public void ClearSection(string section) { if (_sections.TryGetValue(section, out var sec)) { sec.Clear(); } } /// /// 清空所有配置节 /// public void ClearAllSection() { _sections.Clear(); } #endregion Write values }