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#

9 months ago
/* ----------------------------------------------------------
* LINQToINI.cs
*
*
*
* splashcn
*
* http://www.firstsolver.com/wordpress/
*
*
* Visual Studio V2015
* .NET Framework 4 Client Profile
*
*
* V1.2 20160730
* GetProfileSection
*
* V1.1 20121114
*
*
* V1.0 20110630
* LINQini
------------------------------------------------------------ */
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;
}
}
}
}