【IT168技术】昨天看到博客园的Fish Li博友写了一篇关于在.net中读写config文件的各种基本方法,甚是不错,本着与大家分享学习的目的,现把我们项目中对XML格式基础配置文件的读取类与大家分享一下,希望对大家有所帮助。
FileWatcher的特点
通用类的名称为FileWatcher,主要特点如下:
①使用泛型以便能够读取不同类型的XML/Config配置文件,转化成不同的实体类型
②使用Lazy延迟读取,也就是只有在用到的时候才读,不用在Global里初始化
③使用Func方便处理特定的逻辑
④自动监控文件的更改变化
⑤使用非常方便
FileWatcher的用法
在看FileWatcher类源码之前,我们先来看一下基本的用法,首先我们先来准备一些基础数据,如下:
<?xml version="1.0" encoding="utf-8" ?>
<StateProvinceData xmlns="urn:com:company:project:v1">
<Country locale="ABW" hasStateProvinces="true" phonePrefix="297" /> <Country locale="ATG" hasStateProvinces="true" phonePrefix="1 268" />
<Country locale="USA" hasStateProvinces="true" phonePrefix="1" isPostalCodeRequired="true" >
<StateProvince value="Alabama">Alabama</StateProvince>
<StateProvince value="Alaska">Alaska</StateProvince>
<StateProvince value="Arizona">Arizona</StateProvince>
<StateProvince value="Texas">Texas</StateProvince>
<StateProvince value="Utah">Utah</StateProvince>
<StateProvince value="Vermont">Vermont</StateProvince>
<StateProvince value="Virginia">Virginia</StateProvince>
<StateProvince value="Washington">Washington</StateProvince>
<StateProvince value="West Virginia">West Virginia</StateProvince>
<StateProvince value="Wisconsin">Wisconsin</StateProvince>
<StateProvinceData xmlns="urn:com:company:project:v1">
<Country locale="ABW" hasStateProvinces="true" phonePrefix="297" /> <Country locale="ATG" hasStateProvinces="true" phonePrefix="1 268" />
<Country locale="USA" hasStateProvinces="true" phonePrefix="1" isPostalCodeRequired="true" >
<StateProvince value="Alabama">Alabama</StateProvince>
<StateProvince value="Alaska">Alaska</StateProvince>
<StateProvince value="Arizona">Arizona</StateProvince>
<StateProvince value="Texas">Texas</StateProvince>
<StateProvince value="Utah">Utah</StateProvince>
<StateProvince value="Vermont">Vermont</StateProvince>
<StateProvince value="Virginia">Virginia</StateProvince>
<StateProvince value="Washington">Washington</StateProvince>
<StateProvince value="West Virginia">West Virginia</StateProvince>
<StateProvince value="Wisconsin">Wisconsin</StateProvince>
<StateProvince value="Wyoming">Wyoming</StateProvince>
</Country>
<Country locale="UZB" hasStateProvinces="true" phonePrefix="998" />
<Country locale="UZB" hasStateProvinces="true" phonePrefix="998" />
<Country locale="VAT" hasStateProvinces="true" phonePrefix="39" />
</StateProvinceData>
</StateProvinceData>
主要是一个Country集合,每个Country下面有一些特殊的属性以及所拥有的省,这里我们只是节选一段例子。下面我们肯先来创建对于的实例类:
[XmlRoot(Namespace="urn:com:company:project:v1")]
public class StateProvinceData
{
[XmlElement("Country")]
public Country[] Countries { get; set; }
}
[XmlType(Namespace = "urn:com:company:project:v1")]
public class Country
{
[XmlAttribute("locale")]
public string Locale { get; set; }
[XmlIgnore]
public string Name
{
get { return (this.Locale != null) ? CountryName.ResourceManager.GetString(this.Locale) : ""; }
// 这一点比较特殊,主要是从资源文件读取内容,暂时忽略
}
[XmlAttribute("hasStateProvinces")]
public bool HasStateProvinces { get; set; }
[XmlAttribute("isPostalCodeRequired")]
public bool IsPostalCodeRequired { get; set; }
[XmlAttribute("phonePrefix")] public string PhonePrefix { get; set; }
[XmlElement("StateProvince")]
public StateProvince[] StateProvinces { get; set; }
}
[XmlType(Namespace = "urn:com:company:project:v1")]
public class StateProvince
{
[XmlAttribute("value")]
public string Value;
[XmlText]
public string Text;
}
public class StateProvinceData
{
[XmlElement("Country")]
public Country[] Countries { get; set; }
}
[XmlType(Namespace = "urn:com:company:project:v1")]
public class Country
{
[XmlAttribute("locale")]
public string Locale { get; set; }
[XmlIgnore]
public string Name
{
get { return (this.Locale != null) ? CountryName.ResourceManager.GetString(this.Locale) : ""; }
// 这一点比较特殊,主要是从资源文件读取内容,暂时忽略
}
[XmlAttribute("hasStateProvinces")]
public bool HasStateProvinces { get; set; }
[XmlAttribute("isPostalCodeRequired")]
public bool IsPostalCodeRequired { get; set; }
[XmlAttribute("phonePrefix")] public string PhonePrefix { get; set; }
[XmlElement("StateProvince")]
public StateProvince[] StateProvinces { get; set; }
}
[XmlType(Namespace = "urn:com:company:project:v1")]
public class StateProvince
{
[XmlAttribute("value")]
public string Value;
[XmlText]
public string Text;
}
这3个类主要是对应XML文件里的节点元素,通过XML的namespace和XMLAttribute来确保能和XML里的内容对应上。
最后,我们来看一下基本用法:
public static class StateProvinceTable
{
// 通过Lazy达到延迟初始化的目的
// 其参数是一个CreateWatcher委托,用来加载数据
private static Lazy<FileWatcher<IDictionary<string, Country>>> dataWatcher =
new Lazy<FileWatcher<IDictionary<string, Country>>>(CreateWatcher);
//暴露数据给外部使用
public static IDictionary<string, Country> Data
{
get { return dataWatcher.Value.Value; }
}
private static FileWatcher<IDictionary<string, Country>> CreateWatcher()
{
// 传入path和LoadData两个参数
// 其中LoadData参数是Func<FileStream, T>类型的委托,T目前就是IDictionary<string, Country>
return new FileWatcher<IDictionary<string, Country>>
(HttpContext.Current.Server.MapPath("~/StateProvinceData.config"), LoadData);
}
// 用来将FileStream转化成实体集合
private static IDictionary<string, Country> LoadData(FileStream configFile)
{
StateProvinceData dataTable = (StateProvinceData)
(new XmlSerializer(typeof(StateProvinceData))).Deserialize(configFile);
return dataTable.Countries.ToDictionary(item => item.Locale);
}
}
{
// 通过Lazy达到延迟初始化的目的
// 其参数是一个CreateWatcher委托,用来加载数据
private static Lazy<FileWatcher<IDictionary<string, Country>>> dataWatcher =
new Lazy<FileWatcher<IDictionary<string, Country>>>(CreateWatcher);
//暴露数据给外部使用
public static IDictionary<string, Country> Data
{
get { return dataWatcher.Value.Value; }
}
private static FileWatcher<IDictionary<string, Country>> CreateWatcher()
{
// 传入path和LoadData两个参数
// 其中LoadData参数是Func<FileStream, T>类型的委托,T目前就是IDictionary<string, Country>
return new FileWatcher<IDictionary<string, Country>>
(HttpContext.Current.Server.MapPath("~/StateProvinceData.config"), LoadData);
}
// 用来将FileStream转化成实体集合
private static IDictionary<string, Country> LoadData(FileStream configFile)
{
StateProvinceData dataTable = (StateProvinceData)
(new XmlSerializer(typeof(StateProvinceData))).Deserialize(configFile);
return dataTable.Countries.ToDictionary(item => item.Locale);
}
}
这样,我们在任何地方通过引用StateProvinceTable.Data就可以使用了,不需要在Global里初始化加载,不需要自己担心XML数据被更改,直接用就OK了,所有的事情FileWatcher类已经帮你做了。