/* ----------------------------------------------------------
* 文件名称:LINQToINI.cs
*
* 作者:秦建辉
*
* 微信:splashcn
*
* 博客:http://www.firstsolver.com/wordpress/
*
* 开发环境:
* Visual Studio V2015
* .NET Framework 4 Client Profile
*
* 版本历史:
* V1.2 2016年07月30日
* 更新GetProfileSection方法输出
*
* V1.1 2012年11月14日
* 存储文件时,如果目录不存在,则自动创建目录而不是返回失败
*
* V1.0 2011年06月30日
* 基于LINQ实现对ini文件的读写
------------------------------------------------------------ */
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace JwKdsV.Core.HWiNFO
{
///
/// 基于LINQ实现对ini文件的读写
///
internal class LINQToINI
{
///
/// ini文件内容结点结构
///
private struct ININode
{
///
/// 分区名
///
public string section;
///
/// 键名
///
public string keyName;
///
/// 键值
///
public string keyValue;
}
///
/// ini文件内容结点列表
///
private List INIElement = null;
///
/// 读取ini文件并序列化,以供LINQ查询
///
/// ini文件名
/// 是否只做查询操作。缺省为true
/// 文件编码,缺省为null,使用Unicode编码
///
/// true:成功
/// false:失败
///
///
/// 如果只做查询操作,则序列化时去掉空行结点和注释行结点
///
public bool Load(string iniFile, bool isQueryOnly = true, Encoding fileEncoding = null)
{
if (fileEncoding == null)
{ // 默认使用Unicode编码
fileEncoding = Encoding.Unicode;
}
try
{ // 自动检测文件编码
using (StreamReader sr = new StreamReader(iniFile, fileEncoding, true))
{
if (INIElement == null)
{
INIElement = new List();
}
else
{
INIElement.Clear();
}
string Section = null;
while (true)
{
string Source = sr.ReadLine();
if (Source == null) break;
Source = Source.Trim();
if (Source == string.Empty)
{ // 空行
if (!isQueryOnly)
{
INIElement.Add(new ININode { section = "\u000A", keyName = null, keyValue = null });
}
}
else if (Source[0] == '#' || Source[0] == ';')
{ // 注释行
if (!isQueryOnly)
{
INIElement.Add(new ININode { section = "\u000B", keyName = null, keyValue = Source });
}
}
else if (Source[0] == '[')
{ // 分区名
int RightSquareBracketIndex = Source.IndexOf(']');
if (RightSquareBracketIndex != -1)
{
Section = Source.Substring(1, RightSquareBracketIndex - 1).Trim();
if (Section != string.Empty)
{
INIElement.Add(new ININode { section = Section, keyName = string.Empty, keyValue = null });
}
}
}
else
{ // 键名键值对
if (!string.IsNullOrEmpty(Section))
{
int EqualsSignIndex = Source.IndexOf('=');
if (EqualsSignIndex != -1)
{ // 提取键名
string KeyName = Source.Substring(0, EqualsSignIndex).Trim();
if (KeyName != string.Empty)
{ // 提取键值
string KeyValue = Source.Substring(EqualsSignIndex + 1).Trim();
if (KeyValue.Length >= 2)
{ // 判断是否有双引号
if (KeyValue[0] == '\u0022' && KeyValue[KeyValue.Length - 1] == '\u0022')
{
KeyValue = KeyValue.Substring(1, KeyValue.Length - 2);
}
}
INIElement.Add(new ININode { section = Section, keyName = KeyName, keyValue = KeyValue });
}
}
}
}
}
return true;
}
}
catch (System.Exception)
{
return false;
}
}
///
/// 存储ini文件
///
/// 要存储的文件名
/// 文件编码。缺省为null,使用Unicode编码
///
/// true:成功
/// false:失败
///
/// 注意:只有调用此函数,才能保存最终数据
public bool Save(string iniFile, Encoding fileEncoding = null)
{
if (INIElement == null)
{ // 抛出异常:无效的数据源
throw new ApplicationException("Invalid Data Source!");
}
if (fileEncoding == null)
{ // 默认使用Unicode编码
fileEncoding = Encoding.Unicode;
}
try
{
// 获取指定字符串的目录信息
string ToFolder = Path.GetDirectoryName(iniFile); // 注意相对路径
if (!string.IsNullOrEmpty(ToFolder) && !Directory.Exists(ToFolder))
{ // 目录不存在,创建目录
Directory.CreateDirectory(ToFolder);
}
// 写入文件
using (StreamWriter sw = new StreamWriter(iniFile, false, fileEncoding))
{
foreach (ININode node in INIElement)
{
if (node.keyName == null)
{
if (node.section == "\u000A")
{ // 空行
sw.WriteLine();
}
else if (node.section == "\u000B")
{ // 注释行
sw.WriteLine(node.keyValue);
}
}
else
{
if (node.keyName == string.Empty)
{ // 分区
sw.WriteLine("[" + node.section + "]");
}
else
{ // 键名键值对
if (node.keyValue.IndexOf(' ') == -1)
{ // 键值中没有空格
sw.WriteLine(node.keyName + "=" + node.keyValue);
}
else
{ // 键值中包含空格,需在键值两端加上引号
sw.WriteLine(node.keyName + "=\u0022" + node.keyValue + "\u0022");
}
}
}
}
return true;
}
}
catch (System.Exception)
{
return false;
}
}
///
/// 提取键名对应的键值
///
/// 分区名。如果为null,则提取所有的分区名
/// 键名。如果为null,则提取分区所有的键名键值对
/// 缺省键值
/// 键值
public string[] GetProfileString(string section, string keyName, string defaultString = null)
{
if (INIElement == null)
{ // 抛出异常:无效的数据源
throw new ApplicationException("Invalid Data Source!");
}
if (section == null)
{ // 获取所有的分区名
return (from node in INIElement where (node.keyName == string.Empty) select node.section).ToArray();
}
else if (keyName == null)
{ // 获取指定分区所有的键名及键值
return (from node in INIElement where (string.Compare(node.section, section, true) == 0 && !string.IsNullOrEmpty(node.keyName)) select (node.keyName + "=" + node.keyValue)).ToArray();
}
else
{ // 获取键值
var ValueQuery = (from node in INIElement where (string.Compare(node.section, section, true) == 0 && string.Compare(node.keyName, keyName, true) == 0) select node.keyValue).ToArray();
if (ValueQuery.Length == 0)
{
return new string[] { defaultString };
}
else
{
return ValueQuery;
}
}
}
///
/// 提取键名对应的键值(整数值)
///
/// 分区名
/// 键名
/// 缺省键值,默认为0
/// 键值(整数值)
public int GetProfileInt(string section, string keyName, int defaultValue = 0)
{
if (INIElement == null)
{ // 抛出异常:无效的数据源
throw new ApplicationException("Invalid Data Source!");
}
if (string.IsNullOrEmpty(section) || string.IsNullOrEmpty(keyName))
{
return defaultValue;
}
// 获取键值
var ValueQuery = (from node in INIElement where (string.Compare(node.section, section, true) == 0 && string.Compare(node.keyName, keyName, true) == 0) select node.keyValue).ToArray();
if (ValueQuery.Length == 0)
{
return defaultValue;
}
else
{
if (ValueQuery[0] == string.Empty)
{
return defaultValue;
}
else
{ // 将字符串转换为整数值(注意:可能会抛出异常)
return Convert.ToInt32(ValueQuery[0]);
}
}
}
///
/// 获取分区所有的键名键值对
///
/// 分区名
/// 键名键值对数组
public KeyValuePair[] GetProfileSection(string section)
{
if (INIElement == null)
{ // 抛出异常:无效的数据源
throw new ApplicationException("Invalid Data Source!");
}
if (string.IsNullOrEmpty(section))
{
return null;
}
else
{ // 获取指定分区所有的键名及键值
return (from node in INIElement where (string.Compare(node.section, section, true) == 0 && !string.IsNullOrEmpty(node.keyName)) select (new KeyValuePair(node.keyName, node.keyValue))).ToArray();
}
}
///
/// 获取所有的分区名
///
/// 分区名数组
public string[] GetProfileSectionNames()
{
if (INIElement == null)
{ // 抛出异常:无效的数据源
throw new ApplicationException("Invalid Data Source!");
}
// 获取所有的分区名
return (from node in INIElement where (string.Compare(node.keyName, string.Empty, true) == 0) select node.section).ToArray();
}
///
/// 增加或更新分区名、键名或者键值
///
/// 分区名
/// 键名。如果为null或者空串,则删除整个分区
/// 键值。如果为null,则删除该键
///
/// true:成功
/// false:失败
///
public bool WriteProfileString(string section, string keyName, string keyValue)
{
if (string.IsNullOrEmpty(section))
{
return false;
}
if (INIElement == null)
{ // 初始化ini结点列表
INIElement = new List();
}
if (string.IsNullOrEmpty(keyName))
{ // 删除整个分区(关键:要从后往前删)
for (int i = INIElement.Count - 1; i >= 0; i--)
{
if (string.Compare(INIElement[i].section, section, true) == 0 && INIElement[i].keyName != null)
{
INIElement.RemoveAt(i);
}
}
}
else
{ // 更新键值
int InsertIndex = -1;
for (int i = INIElement.Count - 1; i >= 0; i--)
{
if (string.Compare(INIElement[i].section, section, true) == 0)
{
if (string.Compare(INIElement[i].keyName, keyName, true) == 0)
{ // 删除该键
INIElement.RemoveAt(i);
if (keyValue != null)
{ // 更新该键
if (keyValue.Length >= 2)
{ // 判断是否有双引号
if (keyValue[0] == '\u0022' && keyValue[keyValue.Length - 1] == '\u0022')
{
keyValue = keyValue.Substring(1, keyValue.Length - 2);
}
}
// 插入更新后的键名键值对
INIElement.Insert(i, new ININode { section = section, keyName = keyName, keyValue = keyValue });
}
// 直接返回
return true;
}
if (InsertIndex == -1)
{ // 将分区末尾做为插入点
InsertIndex = i + 1;
}
}
}
if (InsertIndex == -1)
{ // 分区不存在,首先增加新的分区名
INIElement.Add(new ININode { section = section, keyName = string.Empty, keyValue = null });
// 再增加新的键名键值对
INIElement.Add(new ININode { section = section, keyName = keyName, keyValue = keyValue });
}
else
{ // 分区存在,在分区末尾增加新的键名键值对
INIElement.Insert(InsertIndex, new ININode { section = section, keyName = keyName, keyValue = keyValue });
}
}
return true;
}
///
/// 替换分区的键名键值对
///
/// 分区名
/// 要替换的键名键值对。如果为null,则删除整个分区
///
/// true:成功
/// false:失败
///
public bool WriteProfileSection(string section, string[] keyValueSet)
{
if (string.IsNullOrEmpty(section))
{
return false;
}
if (INIElement == null)
{ // 初始化ini结点列表
INIElement = new List();
}
// 删除整个分区
int InsertIndex = INIElement.Count;
for (int i = INIElement.Count - 1; i >= 0; i--)
{
if (string.Compare(INIElement[i].section, section, true) == 0 && INIElement[i].keyName != null)
{
INIElement.RemoveAt(i);
InsertIndex = i;
}
}
if (keyValueSet != null)
{ // 写入分区名
INIElement.Insert(InsertIndex++, new ININode { section = section, keyName = string.Empty, keyValue = null });
// 写入键名键值对
foreach (string s in keyValueSet)
{
int EqualsSignIndex = s.IndexOf('=');
if (EqualsSignIndex != -1)
{
string KeyName = s.Substring(0, EqualsSignIndex).Trim();
if (KeyName != string.Empty)
{
string KeyValue = s.Substring(EqualsSignIndex + 1).Trim();
if (KeyValue.Length >= 2)
{ // 判断是否有双引号
if (KeyValue[0] == '\u0022' && KeyValue[KeyValue.Length - 1] == '\u0022')
{
KeyValue = KeyValue.Substring(1, KeyValue.Length - 2);
}
}
INIElement.Insert(InsertIndex++, new ININode { section = section, keyName = KeyName, keyValue = KeyValue });
}
}
}
}
return true;
}
///
/// 将结构数据写入键值
///
/// 分区名
/// 键名
/// 数据
///
/// true:成功
/// false:失败
///
public bool WriteProfileStruct(string section, string keyName, byte[] data)
{
if (string.IsNullOrEmpty(section) || string.IsNullOrEmpty(keyName))
{
return false;
}
if (data == null)
{
return WriteProfileString(section, keyName, null);
}
// 将字节数组转换成16进制字符串
StringBuilder sb = new StringBuilder((data.Length + 1) << 1);
int CheckSum = 0;
foreach (byte b in data)
{
CheckSum += b;
sb.Append(b.ToString("X2"));
}
// 写入校验和
sb.Append(((byte)CheckSum).ToString("X2"));
return WriteProfileString(section, keyName, sb.ToString());
}
///
/// 提取键值,并转化为字节数组
///
/// 分区名
/// 键名
/// 键值对应的字节数组
public byte[] GetProfileStruct(string section, string keyName)
{
if (INIElement == null)
{ // 抛出异常:无效的数据源
throw new ApplicationException("Invalid Data Source!");
}
if (string.IsNullOrEmpty(section) || string.IsNullOrEmpty(keyName))
{
return null;
}
// 获取键值
var ValueQuery = (from node in INIElement where (string.Compare(node.section, section, true) == 0 && string.Compare(node.keyName, keyName, true) == 0) select node.keyValue).ToArray();
if (ValueQuery.Length != 1)
{
return null;
}
// 将16进制字符串转换成字节数组
string s = ValueQuery[0];
if (string.IsNullOrEmpty(s) || (s.Length % 2 != 0))
{
return null;
}
try
{
int Num = s.Length / 2 - 1;
byte[] ValueArray = new byte[Num];
int CheckSum = 0;
for (int i = 0; i < Num; i++)
{
CheckSum += ValueArray[i] = Convert.ToByte(s.Substring(i << 1, 2), 16);
}
// 检测校验和
if (Convert.ToByte(s.Substring(Num << 1, 2), 16) == CheckSum)
{
return ValueArray;
}
else
{ // 校验失败
return null;
}
}
catch (System.Exception)
{ // 无效字符串
return null;
}
}
}
}