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"分隔的,具体的见我前面的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值