C#实现读写ini文件,非调用系统方法

项目里用了很多ini配置文件,并且读写非常频繁。

之前一直用的是调用系统的方法

1         private readonly string _inipath;
2         [DllImport("kernel32", CharSet = CharSet.Auto)]
3         private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
4 
5         [DllImport("kernel32", CharSet = CharSet.Auto)]
6         private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

但最近要改进项目支持维语,发现ini的读写就有问题了

首先是系统的方法不认识维语的文件名

后来花了大把的力气,把文件名改成英文的,结果发现,不能正常读取和写入

无耐只能放弃使用系统的读取方法,在博客园里找到  @幸福★星  https://www.cnblogs.com/xingfustar/archive/2007/09/13/891950.html

这篇博文,就拿来用了,在这里感谢一下@幸福★星

放上去后简单测试发现,效率很低,因为项目里的配置文件多且每个文件的配置项也很多,频繁读取和保存导致系统很卡

就在这个代码上做了一下优化,见正面的代码:

  1  /*----------------------------------------------------------------
  2      * http://XingFuStar.cnblogs.com
  3      *---------------------------------------------------------------*/
  4   /*----------------------------------------------------------------
  5      * 
  6      * 为保证代码的正确性,对INI文件做如下要求:
  7      * 1、以";"开头代表注释,注释要另起一行,不要使用非";"开头的注释
  8      * 2、如果使用了非";"开头的注释,该行中不要包括“=”
  9      * 3、如果使用了非";"开头的注释,对INI进行设置生,该行会被删除
 10      * 
 11      *---------------------------------------------------------------*/
 12         public class IniConfig
 13         {
 14             private string iniPath = "";
 15             private bool isConfig;
 16             private Dictionary<string, List<Property>> propertyList;
 17 
 18             /// <summary>
 19             /// 构造函数:装载配置文件
 20             /// </summary>
 21             /// <param name="iniPath">配置文件的路径</param>
 22             public IniConfig(string iniPath)
 23             {
 24                 this.IniPath = iniPath;
 25             }
 26 
 27             public string IniPath
 28             {
 29                 set
 30                 {
 31                     iniPath = value;
 32                     isConfig = OnIniPataChanged();
 33                 }
 34             }
 35 
 36 
 37             /// <summary>
 38             /// 读取Ini中的配置
 39             /// </summary>
 40             /// <param name="section">节点</param>
 41             /// <param name="key"></param>
 42             /// <returns>读取值</returns>
 43             public string ReadValue(string section, string key)
 44             {
 45                 string value = "";
 46                 bool isRead = false;
 47                 try
 48                 {
 49                     if (propertyList != null && propertyList.ContainsKey(section))
 50                     {
 51                         Property item = propertyList[section].FirstOrDefault(p => p.Key == key);
 52                         if (item != null) return item.Value;
 53                     }
 54                 }
 55                 catch (Exception ex)
 56                 {
 57                     Debug.Print(ex.Message);
 58                 }
 59                 return value;
 60             }
 61 
 62             /// <summary>
 63             /// 向INI中写入配置
 64             /// </summary>
 65             /// <param name="section">节点</param>
 66             /// <param name="key"></param>
 67             /// <param name="value">要写入的新键值</param>
 68             /// <returns>写入是否成功</returns>
 69             public void WriteValue(string section, string key, string value)
 70             {
 71                 bool isWrite = false;
 72                 try
 73                 {
 74                     if (isConfig)
 75                     {
 76                         InitSection(section);
 77                         Property item = propertyList[section].FirstOrDefault(p => p.Key == key);
 78                         if (item != null)
 79                         {
 80                             item.Value = value;
 81                         }
 82                         else
 83                         {
 84                             item = new Property(key,value,""); 
 85                             propertyList[section].Add(item);
 86                         }
 87                         StartSaveIni();
 88                         
 89 
 90                     }
 91                 }
 92                 catch (Exception ex)
 93                 {
 94                     Debug.Print(ex.Message);
 95                 }
 96                // return isWrite;
 97             }
 98 
 99             private long _savingThreads = 0;//是否在执行写入中
100             private void StartSaveIni()
101             {
102                 Action action = () =>
103                 {
104                     if (Interlocked.Read(ref _savingThreads) > 1) return;
105                     Interlocked.Increment(ref _savingThreads);
106                     System.Threading.Thread.Sleep((int)_savingThreads * 500);
107                     SaveIni();
108                     Interlocked.Decrement(ref _savingThreads);
109                 };
110                 action.BeginInvoke(null, null);
111             }
112 
113 
114 
115             /// <summary>
116             /// 移除键值对
117             /// </summary>
118             /// <param name="section"></param>
119             /// <param name="key"></param>
120             public void RemoveItem(string section, string key)
121             {
122                 WriteValue(section, key, null);
123             }
124 
125             /// <summary>
126             /// 验证文件是否存在
127             /// </summary>
128             /// <returns>布尔值</returns>
129             public bool IsExistIniFile()
130             {
131                 return File.Exists(iniPath);
132             }
133 
134             #region 私有方法
135             private bool OnIniPataChanged()
136             {
137                 bool isLoad = false;
138                 try
139                 {
140                     if (File.Exists(iniPath))
141                     {
142                         isLoad = LoadIni();
143                     }
144                 }
145                 catch (Exception ex)
146                 {
147                     Debug.Print(ex.Message);
148                 }
149                 return isLoad;
150             }
151 
152             /// <summary>
153             /// 从文件中加载INI配置信息到列表
154             /// </summary>
155             /// <returns>加载是否成功</returns>
156             private bool LoadIni()
157             {
158                 bool isLoad = false;
159                 try
160                 {
161                     propertyList = new Dictionary<string, List<Property>>();
162                     using (StreamReader stream = new StreamReader(iniPath, System.Text.Encoding.Unicode))
163                     {
164                         string section = "";
165                         while (stream.Peek() != -1)
166                         {
167                             string str = stream.ReadLine().Trim();
168                             //判断该行是否有数据
169                             if (str.Length > 0)
170                             {
171                                 //以“;”开头的行为注释行(硬性规定)
172                                 if (str.Substring(0, 1) != ";")
173                                 {
174                                     //以“[“开头的行为Section行(硬性规定)
175                                     if (str.Substring(0, 1) == "[")
176                                     {
177                                         //记录当前Section
178                                         section = str.Substring(1, str.IndexOf("]") - 1);
179                                         InitSection(section);
180                                     }
181                                     //有“=”的为数据行(硬性规定)
182                                     if (str.IndexOf("=") > 0 && !String.IsNullOrEmpty(section))
183                                     {
184                                         string[] temp = str.Split('=');
185                                         //将该数据行的属性添加到列表
186                                         InitSection(section);
187                                         propertyList[section].Add(new Property(temp[0].Trim(), temp[1].Trim(), ""));
188                                     }
189                                 }
190                                 else if (!String.IsNullOrEmpty(section))
191                                 {
192                                     //将注释行的属性添加到列表
193                                     InitSection(section);
194                                     propertyList[section].Add(new Property("", "", str));
195                                 }
196                             }
197                             else if (!String.IsNullOrEmpty(section))
198                             {
199                                 InitSection(section);
200                                 //为保证格式与加载前相同,因些将空行也加入了列表
201                                 propertyList[section].Add(new Property("", "", ""));
202                             }
203                         }
204                         stream.Close();
205                     }
206                     isLoad = true;
207                 }
208                 catch (Exception ex)
209                 {
210                     Debug.Print(ex.Message);
211                 }
212                 return isLoad;
213             }
214 
215             private void InitSection(string section)
216             {
217                 if(propertyList == null)propertyList = new Dictionary<string, List<Property>>();
218                 if(!propertyList.ContainsKey(section))
219                     propertyList.Add(section,new List<Property>());
220             }
221 
222             /// <summary>
223             /// 将列表中的配置信息保存到INI文件
224             /// </summary>
225             /// <returns>保存是否成功</returns>
226             private bool  SaveIni()
227             {
228                 bool isSave = false;
229                 try
230                 {
231                     using (StreamWriter stream = new StreamWriter(iniPath, false, System.Text.Encoding.Unicode))
232                     {
233                         foreach (var section in propertyList)
234                         {
235                             stream.WriteLine("[" + section.Key + "]");
236 
237                             List<Property> items = section.Value;
238                             foreach (var item in items)
239                             {
240                                 if(item.NeedDelete)continue;
241                                 //写入注释
242                                 if (item.Description != "")
243                                 {
244                                     stream.WriteLine(item.Description);
245                                 }
246                                 //写入键和键值
247                                 if (item.Key != "")
248                                 {
249                                     stream.WriteLine(item.Key + " = " + item.Value);
250                                 }
251                                 //写入空行
252                                 if (item.Key == "" && item.Description == "" && item.Value == "")
253                                 {
254                                     stream.WriteLine("");
255                                 }
256                             }
257                         }
258                         stream.Close();
259                     }
260                    
261                    
262                     isSave = true;
263                 }
264                 catch (Exception ex)
265                 {
266                     Debug.Print(ex.Message);
267                 }
268                 return isSave;
269             }
270 
271             /// <summary>
272             /// 内部类:Ini属性
273             /// </summary>
274             private class Property
275             {
276                 /// <summary>
277                 /// 构造函数
278                 /// </summary>
279                 /// <param name="key"></param>
280                 /// <param name="value"></param>
281                 /// <param name="description"></param>
282                 public Property(string key, string value, string description)
283                 {
284                     this.Key = key;
285                     this.Value = value;
286                     this.Description = description;
287                 }
288                 string key = "";
289                 /// <summary>
290                 ///291                 /// </summary>
292                 public string Key
293                 {
294                     get { return key; }
295                     set { key = value; }
296                 }
297                 string value = "";
298                 /// <summary>
299                 /// 键值
300                 /// </summary>
301                 public string Value
302                 {
303                     get { return this.value; }
304                     set { this.value = value; }
305                 }
306                 string description = "";
307                 /// <summary>
308                 /// 注释
309                 /// </summary>
310                 public string Description
311                 {
312                     get { return description; }
313                     set { description = value; }
314                 }
315 
316                 public bool NeedDelete { get; set; }
317 
318             
319             }
320             #endregion
321         }

改进的地方有以下几点:

1.查询由ArrayList+循环改成用Dictionary + List 然后用Linq查询配置项

2.保存加了异步和延时保存

可能存在的问题:

1.因为保加了延时,不知道会不会出现丢失的可能

2.为了支持维语ini文件改成了unicode编码,对于系统默认的ANSI编码支持没有测试过

总结项目中使用ini的配置不能搞的太复杂,太复杂的不能放在ini里做,还是要想别的办法。

原文地址:https://www.cnblogs.com/linkbiz/p/14146741.html