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
}