You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

595 lines
22 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* ----------------------------------------------------------
* 文件名称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
{
/// <summary>
/// 基于LINQ实现对ini文件的读写
/// </summary>
internal class LINQToINI
{
/// <summary>
/// ini文件内容结点结构
/// </summary>
private struct ININode
{
/// <summary>
/// 分区名
/// </summary>
public string section;
/// <summary>
/// 键名
/// </summary>
public string keyName;
/// <summary>
/// 键值
/// </summary>
public string keyValue;
}
/// <summary>
/// ini文件内容结点列表
/// </summary>
private List<ININode> INIElement = null;
/// <summary>
/// 读取ini文件并序列化以供LINQ查询
/// </summary>
/// <param name="iniFile">ini文件名</param>
/// <param name="isQueryOnly">是否只做查询操作。缺省为true</param>
/// <param name="fileEncoding">文件编码缺省为null使用Unicode编码</param>
/// <returns>
/// true成功
/// false失败
/// </returns>
/// <remarks>
/// 如果只做查询操作,则序列化时去掉空行结点和注释行结点
/// </remarks>
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<ININode>();
}
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;
}
}
/// <summary>
/// 存储ini文件
/// </summary>
/// <param name="iniFile">要存储的文件名</param>
/// <param name="fileEncoding">文件编码。缺省为null使用Unicode编码</param>
/// <returns>
/// true成功
/// false失败
/// </returns>
/// <remarks>注意:只有调用此函数,才能保存最终数据</remarks>
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;
}
}
/// <summary>
/// 提取键名对应的键值
/// </summary>
/// <param name="section">分区名。如果为null则提取所有的分区名</param>
/// <param name="keyName">键名。如果为null则提取分区所有的键名键值对</param>
/// <param name="defaultString">缺省键值</param>
/// <returns>键值</returns>
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;
}
}
}
/// <summary>
/// 提取键名对应的键值(整数值)
/// </summary>
/// <param name="section">分区名</param>
/// <param name="keyName">键名</param>
/// <param name="defaultValue">缺省键值默认为0</param>
/// <returns>键值(整数值)</returns>
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]);
}
}
}
/// <summary>
/// 获取分区所有的键名键值对
/// </summary>
/// <param name="section">分区名</param>
/// <returns>键名键值对数组</returns>
public KeyValuePair<string, string>[] 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<string, string>(node.keyName, node.keyValue))).ToArray();
}
}
/// <summary>
/// 获取所有的分区名
/// </summary>
/// <returns>分区名数组</returns>
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();
}
/// <summary>
/// 增加或更新分区名、键名或者键值
/// </summary>
/// <param name="section">分区名</param>
/// <param name="keyName">键名。如果为null或者空串则删除整个分区</param>
/// <param name="keyValue">键值。如果为null则删除该键</param>
/// <returns>
/// true成功
/// false失败
/// </returns>
public bool WriteProfileString(string section, string keyName, string keyValue)
{
if (string.IsNullOrEmpty(section))
{
return false;
}
if (INIElement == null)
{ // 初始化ini结点列表
INIElement = new List<ININode>();
}
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;
}
/// <summary>
/// 替换分区的键名键值对
/// </summary>
/// <param name="section">分区名</param>
/// <param name="keyValueSet">要替换的键名键值对。如果为null则删除整个分区</param>
/// <returns>
/// true成功
/// false失败
/// </returns>
public bool WriteProfileSection(string section, string[] keyValueSet)
{
if (string.IsNullOrEmpty(section))
{
return false;
}
if (INIElement == null)
{ // 初始化ini结点列表
INIElement = new List<ININode>();
}
// 删除整个分区
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;
}
/// <summary>
/// 将结构数据写入键值
/// </summary>
/// <param name="section">分区名</param>
/// <param name="keyName">键名</param>
/// <param name="data">数据</param>
/// <returns>
/// true成功
/// false失败
/// </returns>
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());
}
/// <summary>
/// 提取键值,并转化为字节数组
/// </summary>
/// <param name="section">分区名</param>
/// <param name="keyName">键名</param>
/// <returns>键值对应的字节数组</returns>
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;
}
}
}
}