.NET平台开源项目速览(5)深入使用与扩展SharpConfig组件
上个月在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧 和 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 中都提到了SharpConfig组件,简单轻量级,速度快,而且还有比较深入的使用介绍。在文章发布后,也有网友提到一些问题,当时我也没仔细去分析,在这次我亲自使用的过程中,就对几个问题进行了比较深入的研究,同时对不满足自己的地方,也进行了扩展。所以今天就把对SharpConfig的源码进行一个简单的分析,同时也根据需求对自己的一个特殊情况进行扩展。自己动手丰衣足食。。。
.NET开源目录:【目录】本博客其他.NET开源项目文章目录
本文原文地址:.NET平台开源项目速览(5)深入使用与扩展SharpConfig组件
1.SharpConfig源码分析
SharpConfig源码并不大,核心代码其实也很简单,就是文件读写,解析。在深入使用和扩展SharpConfig之前,有必要了解一下它的基本结构。所以先来介绍SharpConfig源码中核心的3大类。
Configuration是核心类,我们在前面的文章中只是简单的介绍了一下如何加载配置文件,查看源代码,可以发现加载和保存的方法都是匹配的,都可以从文件或者数据流中加载或者保存。
由于每一个配置文件都包含若干个Section节,所以也可以使用索引来获取这些节,然后操作节下面的设置项。总的来说思路是很简单的。
Configuration在解析过程中,每碰到一个Section,就添加到列表中。而Section的区分就是靠Name,所以,我们在配置文件中注意不要把Section的名称搞混淆了。Section源码中没有特别需要注意的地方,主要是这里检测和移除节点的方法,如下面代码:
/// <summary>检测节中是否存在某个特定名称的设置 </summary>
/// <param name="settingName">设置项的名称</param>
/// <returns>True if the setting is contained in the section; false otherwise.</returns>
public bool Contains(string settingName)
{
return GetSetting(settingName) != null;
} /// <summary>从本节中移除某个名称的设置</summary>
public void Remove(string settingName)
{
if (string.IsNullOrEmpty(settingName))
throw new ArgumentNullException("settingName"); var setting = GetSetting(settingName); if (setting == null)
{
throw new ArgumentException("The specified setting does not exist in the section.");
}
mSettings.Remove(setting);
}
每一个Section下面可以有多个Setting设置。下面看看Setting类的情况。 Setting主要是获取和设置值的方法,如代码:
var someInteger = section["SomeInteger"].GetValue<Boolean>();
float someFloat = section["SomeFloat"].GetValue<float>();
什么只是简单的对SharpConfig 的结构做一个分析,下面我们将针对问题进行跟深入的分析和修改。
2.SharpConfig使用问题与扩展
2.1 读取乱码的问题
第一次发现这个问题并不是我,是网友在看完我的文章介绍后使用,发现读取出来是乱码,不能解析。然后反馈给我。其实问题很简单,只是我也没有注意,其实读取的时候也多个方法可以选择, 默认使用的是null编码设置,系统自动检测,但这非常不保险。最好还是自己把文件的编码写进去。例如:
Configuration config = Configuration.LoadFromFile("example.ini", Encoding.GetEncoding("gb2312"));
这样修改后,如果配置文件中有中文,一般是没问题的。非常重要的一点,如果你读取的时候用了固定编码,修改配置值需要保存的时候,也一定要加上编码,否则会导致其他的配置都发生乱码的情况。如下面的代码:
config.Save("example.ini", Encoding.GetEncoding("gb2312"));
编码的问题,我们可以看一下源码中的情况:
/// <summary>从配置文件直接加载,自动检测编码类型,以及使用默认的设置</summary>
/// <param name="filename">本地配置文件名称</param>
public static Configuration LoadFromFile(string filename)
{
return LoadFromFile(filename, null);
} /// <summary>从配置文件直接加载</summary>
/// <param name="filename">本地配置文件名称</param>
/// <param name="encoding">文件的编码类型,如果为Null,则自动检测</param>
public static Configuration LoadFromFile(string filename, Encoding encoding)
{
if (!File.Exists(filename))
throw new FileNotFoundException("Configuration file not found.", filename); Configuration cfg = null; if (encoding == null)
cfg = LoadFromText(File.ReadAllText(filename));
else
cfg = LoadFromText(File.ReadAllText(filename, encoding)); return cfg;
}
2.2 需要赋空值的情况
碰到这个问题,可能有些变态吧。其实并不是一个问题,如果需要是String,建议直接写一个固定的值,在后台读取的时候进行判断,因为SharpConfig处理的时候,会剔除前后的空白字符。所以这种情况你直接给空字符串是不可取 的,给一个 null,然后后台判断是否==null,然后进行对应操作;如果是数值类型,也可以特定的设置一个值,比如为0,转换 的时候 判断是否为0,否则作为空处理。
2.3 #注释符与字符串冲突的问题
在SharpConfig中,其实有一个可以定义注释符的地方。
/// <summary>获取或者设置 注释标识字符</summary>
public static char[] ValidCommentChars
{
get { return mValidCommentChars; }
set
{
if (value == null) throw new ArgumentNullException("value");
if (value.Length == )
{
throw new ArgumentException("The comment chars array must not be empty.","value");
}
mValidCommentChars = value;
}
}
在配置类的静态构造函数中,默认给了这几个字符作为标识符:
//静态构造函数,设置这些默认值,因此可以修改
static Configuration()
{
mNumberFormat = CultureInfo.InvariantCulture.NumberFormat;
mValidCommentChars = new[] { '#', ';', '\'' };
mIgnoreInlineComments = false;
mIgnorePreComments = false;
}
所以如果配置文件中值可能会出现#号的情况,那你就找一个不出现的 字符,来单独作为你的注释标记符,给这个静态属性赋值即可。
2.4 字符串需要换行的问题
这个问题也很有意思。如果是一行固定文本,你放在配置文件,会自动显示换行,但是读取的时候,人家是看做一行的。因为没有换行符结尾。而如果有几段字符,换行符分割开了,这个时候SharpConfig是肯定不支持的,我们可以看一下SharpConfig中核心的解析函数:
//根据字符串解析配置文件,核心的解析函数
private static Configuration Parse(string source)
{
//重置临时字段
mLineNumber = ; Configuration config = new Configuration();
Section currentSection = null;
var preComments = new List<Comment>(); using (var reader = new StringReader(source))
{
string line = null; // 读取一行,直到结尾(Read until EOF.)
while ((line = reader.ReadLine()) != null)
{
mLineNumber++;
//删除前后空白字符
line = line.Trim(); //这里扩展核心的换行支持,使用 3个 ... 开头,说明是上一个设置的换行
//每一次行都读取下一行试一下,如果有...,就添加
if(line.StartsWith("..."))
{
var text = "\r\n" + line.Substring();
currentSection[currentSection.SettingCount - ].Value += text;
continue;
}
//如果是空行跳过
if (string.IsNullOrEmpty(line)) continue; int commentIndex = ;
var comment = ParseComment(line, out commentIndex); if (!mIgnorePreComments && commentIndex == )
{
// 解析注释行,添加到 注释列表中去
preComments.Add(comment);
continue;
}
else if (!mIgnoreInlineComments && commentIndex > )
{
// 去掉这一行的注释
line = line.Remove(commentIndex).Trim();
} //如果开始字符是 [ ,说明是 节(Sections)
if (line.StartsWith("["))
{
#region 节解析
currentSection = ParseSection(line); if (!mIgnoreInlineComments)
currentSection.Comment = comment; if (config.Contains(currentSection.Name))
{
throw new ParserException(string.Format(
"The section '{0}' was already declared in the configuration.",
currentSection.Name), mLineNumber);
} if (!mIgnorePreComments && preComments.Count > )
{
currentSection.mPreComments = new List<Comment>(preComments);
preComments.Clear();
} config.mSections.Add(currentSection);
#endregion
}
else //否则就是键值设置行
{
//解析设置行
Setting setting = ParseSetting(line); if (!mIgnoreInlineComments) setting.Comment = comment; if (currentSection == null) throw new ParserException(string.Format("The setting '{0}' has to be in a section.", setting.Name), mLineNumber); if (currentSection.Contains(setting.Name)) throw new ParserException(string.Format("The setting '{0}' was already declared in the section.", setting.Name), mLineNumber); if (!mIgnorePreComments && preComments.Count > )
{
setting.mPreComments = new List<Comment>(preComments);
preComments.Clear();
}
currentSection.Add(setting);
} }
}
return config;
}
上面我进行了注释的翻译,从流程可以看到,SharpConfig是依次读取每一行直接进行转换,看看满足什么特征,然后进行处理。如果直接换行,没有Name和=号对应,那会报错。所以我们自己动手,扩展一下,其实非常简单。
上述代码是我已经扩展好的,思路很简单,我们选得一个标记字符串,这里使用“...”作为值换行的标记,每一次读取新行的值后,我们先进行换行判断,如果包含"...",就默认作为当前节最后一个Setting的附加值,手动加上换行符"\r\n"。所以核心的代码其实很简单,主要是你要搞清楚流程,要加在哪里:
//这里扩展核心的换行支持,使用 3个 ... 开头,说明是上一个设置的换行
//每一次行都读取下一行试一下,如果有...,就添加
if(line.StartsWith("..."))
{
var text = "\r\n" + line.Substring();
currentSection[currentSection.SettingCount - ].Value += text;
continue;
}
我们看一个例子,来测试一下换行值的情况,下面是配置文件:
控制台直接读取这个值的代码:
//按文件名称加载配置文件
Configuration config = Configuration.LoadFromFile("example.ini",
Encoding.GetEncoding("gb2312"));
Section section = config["General"];
string someString = section["SomeString"].Value;
Console.WriteLine("字符串SomeString值:{0}", someString);
结果如下,已经默认进行换行了:
3.资源
现在写博客频繁了,也有大量代码,所以开始使用github,这次就作为我的第一个开源项目代码吧,把我修改后的源码发在上面,大家去下载好了。
另外,我也对SharpConfig进行了翻译,可以便于大家更方便的使用,源码可以去github的地址下载,帮助文档也在里面哦。这里先截个图:
这个帮助文档也是使用:.NET平台开源项目速览(4).NET文档生成工具ADB及使用 文章中的ADB工具来生成的,非常好用。
文档和源码下载地址:https://github.com/asxinyu/Improved_SharpConfig
.NET平台开源项目速览(5)深入使用与扩展SharpConfig组件的更多相关文章
- .NET平台开源项目速览(2)Compare .NET Objects对象比较组件
.NET平台开源项目速览今天介绍一款小巧强大的对象比较组件.可以更详细的获取2个对象的差别,并记录具体差别,比较过程和要求可以灵活配置. .NET开源目录:[目录]本博客其他.NET开源项目文章目录 ...
- .NET平台开源项目速览(14)最快的对象映射组件Tiny Mapper
好久没有写文章,工作甚忙,但每日还是关注.NET领域的开源项目.五一休息,放松了一下之后,今天就给大家介绍一个轻量级的对象映射工具Tiny Mapper:号称是.NET平台最快的对象映射组件.那就一起 ...
- .NET平台开源项目速览(4).NET文档生成工具ADB及使用
很久以前就使用ADB这个工具来生成项目的帮助文档.功能强大,在学习一些开源项目的过程中,官方没有提供CHM帮助文档,所以为了快速的了解项目结构和注释.就生成文档来自己看,非常好用.这也是一个学习方法吧 ...
- .NET平台开源项目速览-最快的对象映射组件Tiny Mapper之项目实践
心情小札:近期换了工作,苦逼于22:00后下班,房间一篇狼藉~ 小翠鄙视到:"你就适合生活在垃圾堆中!!!" 晚上浏览博客园 看到一篇非常实用的博客:.NET平台开源项目速览(14 ...
- .NET平台开源项目速览(17)FluentConsole让你的控制台酷起来
从该系列的第一篇文章 .NET平台开源项目速览(1)SharpConfig配置文件读写组件 开始,不知不觉已经到第17篇了.每一次我们都是介绍一个小巧甚至微不足道的.NET平台的开源软件,或者学习,或 ...
- .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
不知不觉,“.NET平台开源项目速览“系列文章已经15篇了,每一篇都非常受欢迎,可能技术水平不高,但足够入门了.虽然工作很忙,但还是会抽空把自己知道的,已经平时遇到的好的开源项目分享出来.今天就给大家 ...
- .NET平台开源项目速览(13)机器学习组件Accord.NET框架功能介绍
Accord.NET Framework是在AForge.NET项目的基础上封装和进一步开发而来.因为AForge.NET更注重与一些底层和广度,而Accord.NET Framework更注重与机器 ...
- .NET平台开源项目速览(1)SharpConfig配置文件读写组件
在.NET平台日常开发中,读取配置文件是一个很常见的需求.以前都是使用System.Configuration.ConfigurationSettings来操作,这个说实话,搞起来比较费劲.不知道大家 ...
- .NET平台开源项目速览(12)哈希算法集合类库HashLib
.NET的System.Security.Cryptography命名空间本身是提供加密服务,散列函数,对称与非对称加密算法等功能.实际上,大部分情况下已经满足了需求,而且.NET实现的都是目前国际上 ...
随机推荐
- css 简析folat
1.float?? 不知道大家是否还记得之前我们讲过页面是文档流,具体什么是文档流,我就不说了?于是我们页面布局如果用div的话,那么块状的元素是怎么排列的,什么叫块状自己去看? 如果我们呢用div布 ...
- postman测试接口之POST提交本地文件数据
前言: 接口测试时,有时需要读取文件的数据:那么postman怎么添加一个文件作为参数呢? 实例: 接口地址: http://121.xxx.xxx.xxx:9003/marketAccount/ba ...
- weex image
weex 的image用来渲染图片, 可以使用img作为它的别名. 需要注意的是,他的长度可宽度必须指定, 不然它是不会工作的. 它没有任何的子组件. 有两个属性: src 用来指定图片的地址图片. ...
- Java反编译代码对齐
使用反编译的代码作为jar包源码进行调试时,经常会遇到的情况是反编译后的源码之在注释里包含行号,但是与代码所在行经常对应不上.这个时候,就有必要对代码进行对齐了. public class Reo ...
- JVM中对象的销毁
1.可达性分析算法: 可达性分析算法用来寻找将要销毁的对象,它的基本思路是:通过一系列的称为“GC ROOTs”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链,当一个对象到GC ...
- 在线图片压缩后以ImageIO 流的形式 设置大小显示指定页面
1.Servlet 代码 public class ZoomImgServlet extends HttpServlet implements Servlet { public void init ...
- java并发编程(十五)内存可见两种方式 加锁和volatile
1.volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制. ...
- Google云平台对于2014世界杯半决赛的预测,德国阿根廷胜!
由于本人是个足球迷,前段日子Google利用自己云平台预测世界杯八进四的比赛并取得了75%的正确率的事情让我振动不小.虽然这些年一直听说大数据的预测和看趋势能力如何如何强大,但这次的感受更加震撼,因为 ...
- <2048>调查报告心得与体会
老师这次给我们布置了一个任务,就是让我们写一份属于自己的调查报告,针对这个任务,我们小组的六个人通过积极的讨论,提出了一些关于我们产品的问题,当然这些问题并不是很全面,因为我们是从自己的角度出发,无法 ...
- VS2013.3 & VS2014 任务资源管理器
Web 开发,特别是前端 Web 开发,正迅速变得像传统的后端开发一样复杂和精密.前端生成过程,可以囊括SASS 和LESS扩展.CSS/JS的压缩包.JSHint 或 JSLint的运行时 .或者更 ...