原创 C# 正则表达式 读写 Ini 文件
昨天遇到读ini文件的问题,我知道C#里没有提供相应的类,所有的.net配置都是xml方式存储的。
读取ini文件,很多人直接google一把,然后添加dll引用。介绍的比较详细的,如: C#如何读写和创建INI文件
那么,如果不引用api呢? 我想到了正则表达式,分别读取section与key value,然后再匹配。刚好网上有一个类似的文章 用正则表达式读取INI文件
看了下他的内容,然后再整理下思路,OK,我自己的Helper就出来了。
namespace goldli.Utility.Library { public interface IPosition { int Position { get; set; } } public class IniKey : IPosition { public string Name { get; set; } public string Value { get; set; } public int Position { get; set; } } public class IniSection : Collection<IniKey>, IPosition { /// <summary> /// Section名称 /// </summary> public string Name { get; set; } /// <summary> /// section在文件里位置,用于与KeyValue对比 /// </summary> public int Position { get; set; } public IniKey Add(string keyName) { var result = Find(keyName); if (result == null) { var key = new IniKey{Name = keyName}; Add(key); } return result; } public void Remove(string keyName) { var key = Find(keyName); if (key == null) return; Remove(key); } public override IniKey Find(object value) { var keyName = value as string; if(string.IsNullOrEmpty(keyName)) throw new ArgumentNullException("value"); IniKey result = null; Lock(); foreach (IniKey key in List) { if (!Tools.IsSameString(key.Name, keyName)) continue; result = key; break; } UnLock(); return result; } /// <summary> /// 判断一个key是否存在 /// </summary> /// <param name="keyName"></param> /// <returns></returns> public bool KeyIsExist(string keyName) { return Find(keyName) != null; } /// <summary> /// 读取一个值 /// </summary> /// <param name="keyName"></param> /// <returns></returns> public string ReadValue(string keyName) { var key = Find(keyName); return key != null ? key.Value : null; } /// <summary> /// 写入一个值 /// </summary> /// <param name="keyName"></param> /// <param name="value"></param> public void WriteValue(string keyName,string value) { Add(keyName).Value = value; } } public class Sections :Collection<IniSection> { /// <summary> /// 查找 /// </summary> /// <param name="value">Section.Name</param> /// <returns></returns> public override IniSection Find(object value) { var sectionName = value as string; if (string.IsNullOrEmpty(sectionName)) throw new ArgumentNullException("value"); IniSection result = null; Lock(); foreach (IniSection section in List) { if (!Tools.IsSameString(section.Name,sectionName)) continue; result = section; break; } UnLock(); return result; } } /// <summary> /// Ini文件读写类 /// </summary> public class IniHelper { private IniKey[] _array; private int _arrarIndex; private const string ExpSection = "(?<=\\[)\\w+(?=\\]\\r)"; /// <summary> /// 注:你要保证键值对中值不为空,即使是空字符串也不行 /// </summary> private const string ExpKeyValue = "^(?<key>(?!;).+?)\\s*=\\s*(?<value>.*(?=\\r))"; //ini文件 private readonly string _fileName; private void ExtractKeyValues(string data) { try { var regexObj = new Regex(ExpKeyValue, RegexOptions.Multiline); var mc = regexObj.Matches(data); if (mc.Count > 0) { _array = new IniKey[mc.Count]; for (var i = 0; i < mc.Count; i++) { var m = mc[i].Groups; var key = new IniKey { Name = m[1].Value, Value = m[2].Value, Position = m[1].Index }; _array[i] = key; } } else { throw new RankException("error when regex key values."); } } catch (Exception ex) { Sections.Clear(); throw; } } private void ExtractSections(string data) { try { var regexObj = new Regex(ExpSection); var matchResults = regexObj.Match(data); while (matchResults.Success) { var g = matchResults.Groups[0]; var section = new IniSection { Name = g.Value, Position = g.Index }; Sections.Add(section); matchResults = matchResults.NextMatch(); } } catch (Exception ex) { Sections.Clear(); throw; } } /// <summary> /// 根据起始位置查找keyvalue /// </summary> /// <param name="section"></param> /// <param name="next"></param> private void FillSection(IniSection section,int next) { for (var i = _arrarIndex; i < _array.Length; i++) { var key = _array[i]; if ((section.Position < key.Position) && (key.Position < next)) { section.Add(key); _arrarIndex++; } else break; } } private void FillSections() { _arrarIndex = 0; for (var i = 0; i < Sections.Count; i++) { var section = Sections[i]; var next = int.MaxValue; if ((i + 1) != Sections.Count) next = Sections[i + 1].Position; FillSection(section,next); } Array.Clear(_array,0,_array.Length); } public IniHelper(string fileName) { _fileName = fileName; Sections =new Sections(); } /// <summary> /// 文件编码 /// </summary> public Encoding FileEncoding { get; set; } /// <summary> /// 加载文件 /// </summary> public void Load() { var data = FileReadWriteHelper.Read(_fileName, FileEncoding.WebName); if (string.IsNullOrEmpty(data)) throw new FileLoadException(_fileName); ExtractSections(data); ExtractKeyValues(data); FillSections(); } /// <summary> /// 保存文件 /// </summary> public void Save(string fileName) { var iniBuilder = new StringBuilder(); foreach (IniSection section in Sections) { var aSection = string.Format("[{0}]\r\n", section.Name); iniBuilder.Append(aSection); foreach (IniKey key in section) { var aKeyValue = string.Format("{0}={1}\r\n", key.Name, key.Value); iniBuilder.Append(aKeyValue); } iniBuilder.Append(Environment.NewLine); } FileReadWriteHelper.Write(fileName, iniBuilder.ToString(), FileEncoding.WebName); } public IniSection Add(string sectionName) { var section = Sections.Find(sectionName); if (section == null) { section = new IniSection {Name = sectionName}; Sections.Add(section); } return section; } public void Add(IniSection section) { var tmp = Sections.Find(section.Name); if (tmp == null) Sections.Add(section); } public void Remove(string sectionName) { var section = Sections.Find(sectionName); if (section == null) return; Sections.Remove(section); } public void Remove(IniSection section) { var tmp = Sections.Find(section.Name); if (tmp == null) return; Sections.Remove(section); } public Sections Sections { get; private set; } } }
使用示例
var ini = new IniHelper(@"i:\spring.ini"); ini.FileEncoding = Encoding.ASCII; ini.Load(); textBox1.Clear(); foreach (IniSection section in ini.Sections) { extBox1.AppendText("[" + section.Name +"]\r\n"); foreach (IniKey key in section) { textBox1.AppendText(key.Name + " = " + key.Value + "\r\n"); } }
哈哈,其实挺简单的。主要的问题是把正则写正确。