在.NET中读写INI文件 ——兼谈正则表达式的应用

INI 文件是 Windows 平台上的一种较常用的软件配置文件格式, Windows 应用程序常常使用它来保存一些配置信息。它一般是由数个包含 key-value 对的 Section 组成,每个 key-value 对保存着一些软件配置信息。例如最典型的 NT 系列的启动配置文件 boot.ini :


[boot loader]

timeout=30

default=multi(0)disk(0)rdisk(0)partition(2)\WINDOWS

[operating systems]

multi(0)disk(0)rdisk(0)partition(2)\WINDOWS="Microsoft Windows XP Professional" /fastdetect

multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /fastdetect


在这个文件中,方括号中的字符串是

Section 的名字,两个方括号之间的内容为一个 Section 。 Section 的内容是一些 key-value 对,每个 key-value 对占据一行,例如 timeout=30 就是一对 key-value 对, timeout 是 key ,对应的 value 是 30 。 Windows 平台专门提供了一组 API 可以方便地操作 INI 文件,例如 GetPrivateProfileSection() 、 GetPrivateProfileInt() 等。

随着 Windows 系列操作系统的不断发展, INI 文件的作用逐渐被注册表、 XML 格式的 config 文件等所取代,很少再用于系统配置,但我们仍可以在应用程序中使用它。在 .NET 平台上推荐使用的软件配置文件格式是基于 XML 的 config 文件,因此在 .NET Framework 中并没有提供对 INI 文件读写的特殊支持,使得我们有时在需要读写 INI 文件时不是很方便。本文将探讨如何使 INI 文件的读写在 .NET 平台上变得更加容易。当然,我们可以直接引入上述的 API ,但本文将不使用 API ,而是完全基于 .NET Framework 。

** 创建 ** ** INI ** ** 文件读写类 ** ** **

要在 .NET 平台上处理 INI 文件,很自然的想法就是创建一个专门的 class 来负责 INI 文件的读写工作,这个 class 暴露适当的接口供外部调用。一般的 INI 文件的尺寸很小,因此最简单的做法就是以文本的方式将整个文件读入一个 string 变量中。类定义如下:


public class FileIni

{

private string fileContents = null ;

public FileIni( string fileName)

{

if (File.Exists(fileName))

{

StreamReader r = File.OpenText(fileName);

fileContents = r.ReadToEnd();

r.Close();

}

}

}


接下来我们要提供一些方法来操作这个字符串,比如从中返回所有的 Section Name 、取得特定的 key 所对应的 value 等。我们可以使用字符串查找之类的方法来完成这些工作,但是 .NET Framework 为我们提供了更好的方法,那就是正则表达式。

** 正则表达式 ** ** **

所谓正则表达式是一种被设计用来优化字符串操作的语言。它使用一组元字符( Metacharacters )来实现强劲的字符串操作能力。这组元字符最早来自于对 DOS 文件系统中 ? 和 * 的扩展。在 DOS 文件系统中, ? 和 * 分别被用来代替单个字符和字符群组,它们可以被认为是最早的元字符。正则表达式在它们的基础上不断扩充,形成了一套元字符集,能够表达非常复杂的字符串。

举例来说,网上注册时常常需要用户输入一个有效的 Email 地址。当用户输入一个字符串后,我们如何验证这个 Email 地址是否合法呢?使用下面这个正则表达式可以轻易地实现目的:


@"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$"


关于这个正则比表达式的含义,在此不做过多解释,有兴趣的朋友可以参考相关的正则表达式资料。这个正则表达式虽不能保证用户输入的

Email 地址 100% 的真实有效,但至少可以保证用户输入的 Email 地址看上去是合法有效的。

.NET Framework 中提供了一些使用正则表达式的类,这些类位于 System.Text.RegularExpressions 名字空间下。

** 使用正则表达式实现 ** ** FileIni ** ** 类的功能 ** ** **

现在我们可以使用正则表达式来实现 FileIni 类的相应功能了。为了返回 INI 文件中所有 Section 的名字,我们可以使用一个只读属性 SectionNames 来返回一个 Section Name 的字符串数组。


public string [] SectionNames

{

get

{

// Using regular expression to get all section names.

string regexPattern = @"\[(?

 1<sectionname>\w*)\\]"; 
 2
 3Regex r =  new  Regex(regexPattern);  // Match "[anywords]" 
 4
 5MatchCollection matches = r.Matches(fileContents); 
 6
 7// Writing all section names to a string array. 
 8
 9string  [] results =  new  string  [matches.Count]; 
10
11for  (  int  i = 0; i &lt; matches.Count; i++) 
12
13{ 
14
15results[i] = matches[i].Result("${SectionName}"); 
16
17} 
18
19return  results; 
20
21} 
22
23} 
24
25* * *
26
27在上面的代码中,我们使用一个正则表达式: 
28
29@"\\[(?<sectionname>\w*)\\]"  ,对源字符串进行一次匹配就取出了所有的  Section Name  。 
30
31为了取得特定  Section  下的特定的  key  的  value  ,我们先要取得此  Section  下的所有内容,然后再从中取出特定  key  的  value  。 
32
33* * *
34
35public  string  GetSectionString(  string  sectionName) 
36
37{ 
38
39string  regexPattern = @"(\\[" + sectionName + @"\\]" 
40
41\+ @"(?<sectionstring>.*)\\[)"; 
42
43Regex r =  new  Regex(regexPattern, RegexOptions.Singleline); 
44
45if  (r.IsMatch(fileContents)) 
46
47{ 
48
49return  r.Match(fileContents).Result("${SectionString}"); 
50
51} 
52
53return  string  .Empty; 
54
55} 
56
57* * *
58
59GetSectionString() 
60
61根据特定的  sectionName  取得此  Section  的全部内容。假设  sectionName  为字符串  boot loader  ,此时的正则表达式为  @”(\\[boot loader\\](?<setionstring>.*)\\[]”  。得到  Section  下的所有内容后,我们再从其中得到我们想要的  value  值。 
62
63* * *
64
65public  string  GetKeyString(  string  sectionName,  string  keyName) 
66
67{ 
68
69string  sectionString =  this  .GetSectionString(sectionName); 
70
71string  regexPattern = @"(" + keyName + @"=(?<value>.*)\r\n)"; 
72
73Regex r =  new  Regex(regexPattern); 
74
75if  (r.IsMatch(fileContents)) 
76
77{ 
78
79return  r.Match(fileContents).Result("${value}"); 
80
81} 
82
83return  string  .Empty; 
84
85} 
86
87* * *
88
89在此基础上,可以得到更多的诸如 
90
91GetKeyInt()  之类的方法。至于写方法,利用  Regex  的  Replace()  方法也是很容易实现的,在此就不做过多的叙述了。 
92
93** 总结  ** ** **
94
95本文着重演示了正则表达式在读写  INI  文件时的应用。所实现的  INI  文件读写类  FileIni  扩展性稍显不足,例如,这个类只能处理通用格式的  INI  文件,对于格式稍有变化的  INI  文件,此类中的正则表达式就需要修改了。总之,正则表达式是处理字符串的强大工具,掌握了它 
96
97对我们更高效地处理字符串是绝对有好处的。</value></setionstring></sectionstring></sectionname></sectionname>
Published At
Categories with Web编程
comments powered by Disqus