`
doxingg
  • 浏览: 5248 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

C#操作ini文件

 
阅读更多

转自:http://www.cnblogs.com/gaohades/archive/2006/01/24/322751.html

          http://llxlett.blog.163.com/blog/static/4192736320113323918484/

INI文件其实是一种具有特定结构的文本文件,它的构成分为三部分,结构如下:

[Section1]
key 
1 = value2
key 
1 = value2
……
[Section2]
key 
1 = value1
key 
2 = value2
……

文件由若干个段落(section)组成,每个段落又分成若干个key)和值(value)。Windows系统自带的Win32API函数GetPrivateProfileString()WritePrivateProfileString()分别实现了对INI文件的读写操作,他们位于kernel32.dll下。

但是令人遗憾的是C#所使用的.NET框架下的公共类库并没有提供直接操作INI文件的类,所以唯一比较理想的方法就是调用API函数。

然后,.Net框架下的类库是基于托管代码的,而API函数是基于非托管代码的,(在运行库的控制下执行的代码称作托管代码。相反,在运行库之外运行的代码称作非托管代码。)如何实现托管代码与非托管代码之间的操作呢?.Net框架的System.Runtime.InteropServices命名空间下提供各种各样支持COM interop及平台调用服务的成员,其中最重要的属性之一DllImportAttribute可以用来定义用于访问非托管API的平台调用方法,它提供了对从非托管DLL导出的函数进行调用所必需的信息。下面就来看一下如何实现C#API函数的互操作。

读操作:

[DllImport("kernel32")]
private static extern int GetPrivateProfileString(string section, string key, string defVal, StringBuilder retVal, int size, string filePath); 
section:要读取的段落名
key: 要读取的键
defVal: 读取异常的情况下的缺省值
retVal: key所对应的值,如果该key不存在则返回空值
size: 值允许的大小
filePath: INI文件的完整路径和文件名

写操作:

 

[DllImport("kernel32")] 
private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); 
section: 要写入的段落名
key: 要写入的键,如果该key存在则覆盖写入
val: key所对应的值
filePath: INI文件的完整路径和文件名

 

 

 

2、 INI文件的fileName必须使用绝对路径,说明如下

If the lpFileName parameter does not contain a full path and file name for the file,
WritePrivateProfileString searches the Windows directory for the file. 
If the file does not exist,this function creates the file in the Windows directory.

 

3、封装的方法中,最有价值的是获取所有Sections和所有的Keys,网上关于这个的代码大部分是错误的,这里给出一个正确的方法:

 

/// 返回该配置文件中所有Section名称的集合

public ArrayList ReadSections() {
byte[] buffer = new byte[65535];
int rel = GetPrivateProfileSectionNamesA(buffer, buffer.GetUpperBound(0), _FileName);
int iCnt, iPos;
ArrayList arrayList = new ArrayList();
string tmp;
if (rel>0) {
iCnt = 0; iPos = 0; 
for (iCnt = 0; iCnt < rel; iCnt++) {
if (buffer[iCnt] == 0x00) {
tmp =System.Text.ASCIIEncoding.Default.GetString(buffer, iPos, iCnt-iPos ).Trim();
iPos = iCnt + 1;
if (tmp != "")
arrayList.Add(tmp);
}
}
}
return arrayList;
}

// 获取节点的所有KEY值

public ArrayList ReadKeys(string sectionName) {

byte[] buffer = new byte[5120];
int rel = GetPrivateProfileStringA(sectionName, null, "", buffer, buffer.GetUpperBound(0), _FileName);

int iCnt, iPos;
ArrayList arrayList = new ArrayList();
string tmp;
if (rel > 0) {
iCnt = 0; iPos = 0;
for (iCnt = 0; iCnt < rel; iCnt++) {
if (buffer[iCnt] == 0x00) {
tmp = System.Text.ASCIIEncoding.Default.GetString(buffer, iPos, iCnt-iPos).Trim();
iPos = iCnt + 1;
if (tmp != "")
arrayList.Add(tmp);
}
}
}
return arrayList;
}

 

4、批判网上一个常见的代码范例

public string ReadString(string Section, string Key) {
StringBuilder buffer= new StringBuilder(65535); 
GetPrivateProfileString(Section, Key, "", buffer, buffer.Capacity, _FileName); 
return buffer.ToString(); 
}

用StringBuilder只能读出第一行,不是一个好的写法,正确的做法应该是用char[],因为返回的是一个二进制的串,字符串之间是用"\0"分隔的,具体的见我前面的代码。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics