定义一个管理配置文件的类

来源:互联网 发布:专业网速测试软件 编辑:程序博客网 时间:2024/05/02 01:29

读他人源码,摘录一些好代码

public class Configuration
{
    private XmlDocument xmlDoc;
    private string xmlPath;
    private Hashtable basicValues;
    private Hashtable arrayValues; /// <summary>
    /// 获取基本配置中的字符串类型键值。
    /// </summary>
    /// <param name="key">配置字段的索引。</param>
    /// <returns>找到返回字符串,否则返回 null。</returns>
    public string GetString(string key)
    {
        key = key.ToLower();
        return basicValues.ContainsKey(key) ?
            _SafeGetString((string)basicValues[key]) : null;
    }

    /// <summary>
    /// 读取基本配置中的字符串类型键值。
    /// </summary>
    /// <param name="key">配置字段的索引。</param>
    /// <param name="defaultValue">找不到指定字段时返回的默认值。</param>
    /// <returns>找到返回字符串,否则返回 defaultValue。</returns>
    public string ReadString(string key, string defaultValue)
    {
        key = key.ToLower();
        return basicValues.ContainsKey(key) ?
            _SafeGetString((string)basicValues[key]) : defaultValue;
    }

    /// <summary>
    /// 设置基本配置中的字符串类型键值。
    /// </summary>
    /// <param name="key">配置字段的索引。</param>
    /// <param name="value">配置字段的值。</param>
    public void WriteString(string key, string value)
    {
        key = key.ToLower();
        basicValues[key] = value;
    }

    /// <summary>
    /// 读取基本配置中的 Int32 类型键值。
    /// </summary>
    /// <param name="key">配置字段的索引。</param>
    /// <param name="defaultValue">找不到指定字段或字段值不合法时返回的默认值。</param>
    /// <returns>找到并返回合法的 Int32 值,否则返回 defaultValue。</returns>
    public int ReadInt32(string key, int defaultValue)
    {
        int ret = 0;
        if (!int.TryParse(ReadString(key, defaultValue.ToString()), out ret))
            return defaultValue;
        else
            return ret;
    }

    /// <summary>
    /// 设置基本配置中的 Int32 类型键值。
    /// </summary>
    /// <param name="key">配置字段的索引。</param>
    /// <param name="value">配置字段的值。</param>
    public void WriteInt32(string key, int value)
    {
        WriteString(key, value.ToString());
    }

    /// <summary>
    /// 读取基本配置中的 Boolean 类型键值。
    /// </summary>
    /// <param name="key">配置字段的索引。</param>
    /// <param name="defaultValue">找不到指定字段或字段值不合法时返回的默认值。</param>
    /// <returns>找到并返回合法的 Boolean 值,否则返回 defaultValue。</returns>
    public bool ReadBoolean(string key, bool defaultValue)
    {
        bool ret = false;
        if (!bool.TryParse(ReadString(key, defaultValue.ToString()), out ret))
            return defaultValue;
        else
            return ret;
    }

    /// <summary>
    /// 设置基本配置中的 Boolean 类型键值。
    /// </summary>
    /// <param name="key">配置字段的索引。</param>
    /// <param name="value">配置字段的值。</param>
    public void WriteBoolean(string key, bool value)
    {
        WriteString(key, value.ToString());
    }

    /// <summary>
    /// 移除基本配置中的键值。
    /// </summary>
    /// <param name="key">字段的索引。</param>
    public void DeleteValue(string key)
    {
        key = key.ToLower();

        if (basicValues.ContainsKey(key))
            basicValues.Remove(key);
    }

    /// <summary>
    /// 暴露整个配置文件的文档结构。<br />
    /// 虽然不是良好的范例,但是我觉得这样在此处比较合理。
    /// </summary>
    public XmlDocument XmlDocument
    {
        get
        {
            return xmlDoc;
        }
    }

    /// <summary>
    /// 取得命名数组配置对象。
    /// </summary>
    /// <param name="name">数组名称。</param>
    /// <returns>找到命名对象则返回该对象,否则返回 null。</returns>
    public string[] GetArray(string name)
    {
        name = name.ToLower();
        return (string[])arrayValues[name];
    }

    /// <summary>
    /// 以安全访问的方式取得数组配置对象。
    /// </summary>
    /// <param name="name">数组名称。</param>
    /// <returns>找到命名对象则返回该对象,否则返回空的字符串数组实例。</returns>
    public string[] SafeGetArray(string name)
    {
        string[] arr = GetArray(name);
        return arr != null ? arr : new string[0];
    }

    /// <summary>
    /// 设置命名数组配置对象(整体赋值)。
    /// </summary>
    /// <param name="name">数组名称。</param>
    /// <param name="array">要设置成的数组。</param>
    public void SetArray(string name, string[] array)
    {
        name = name.ToLower();
        if (array == null)
            throw new ArgumentNullException("array");

        arrayValues[name] = array;
    }

    /// <summary>
    /// 取得命名数组某项值。
    /// </summary>
    /// <param name="name">数组名称。</param>
    /// <param name="index">项在数组中的索引。</param>
    /// <returns>如果没有找到数组返回 null。如果索引越界则引发。</returns>
    /// <exception cref="IndexOutOfRangeException"></exception>
    public string GetArrayItem(string name, int index)
    {
        string[] arr = GetArray(name);
        if (arr != null)
        {
            if (index >= 0 && index < arr.Length)
                return arr[index];
            else
                throw new IndexOutOfRangeException();
        }
        else
            return null;
    }

    /// <summary>
    /// 设置命名数组某项值。
    /// </summary>
    /// <param name="name">数组名称。</param>
    /// <param name="index">项在数组中的索引。</param>
    /// <param name="value">要设置成的值。</param>
    /// <exception cref="IndexOutOfRangeException"></exception>
    /// <exception cref="InvalidOperationException">当数组不存在时抛出。</exception>
    public void SetArrayItem(string name, int index, string value)
    {
        string[] arr = GetArray(name);
        if (arr != null)
        {
            if (index >= 0 && index < arr.Length)
                arr[index] = value;
            else
                throw new IndexOutOfRangeException();
        }
        else
        {
            throw new InvalidOperationException(string.Format("数组 {0} 不存在。", name));
        }
    }

    /// <summary>
    /// 移除数组配置中的数组。
    /// </summary>
    /// <param name="name">数组的名称。</param>
    public void DeleteArray(string name)
    {
        name = name.ToLower();

        if (arrayValues.ContainsKey(name))
            arrayValues.Remove(name);
    }

    /// <summary>
    /// 新建一个 Configuration 类的实例。
    /// </summary>
    /// <param name="configPath">配置文件路径</param>
    public Configuration(string configPath)
    {
        if (configPath == null)
        {
            throw new ArgumentNullException("configPath");
        }
        xmlPath = configPath;

        // 读入配置
        try
        {
            loadConfig();
        }
        catch
        {
            xmlDoc = new XmlDocument();
            basicValues = new Hashtable();
            arrayValues = new Hashtable();

            XmlNode xmlNd = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
            xmlDoc.AppendChild(xmlNd);
            xmlNd = xmlDoc.CreateNode(XmlNodeType.Element, "revolution", "");
            xmlDoc.AppendChild(xmlNd);
        }
    }

    /// <summary>
    /// 保存配置文件。
    /// </summary>
    /// <exception cref="AiryAi.Revolution.Core.Exceptions.ConfigurationException"></exception>
    public void SaveConfig()
    {
        saveConfig();
    }

    /// <summary>
    /// 重新载入配置文件。
    /// </summary>
    /// <exception cref="AiryAi.Revolution.Core.Exceptions.ConfigurationException"></exception>
    public void ReloadConfig()
    {
        // 备份原有数据
        Hashtable _basicValues = basicValues;
        Hashtable _arrayValues = arrayValues;
        XmlDocument _xmlDoc = xmlDoc;

        // 尝试载入数据
        try
        {
            loadConfig();
        }
        catch
        {
            basicValues = _basicValues;
            xmlDoc = _xmlDoc;
            arrayValues = _arrayValues;

            throw;
        }

        // 销毁备份
        _arrayValues = null;
        _basicValues = null;
        _xmlDoc = null;
    }

    private string _SafeGetString(string str)
    {
        return str != null ? str : String.Empty;
    }

    private void saveConfig()
    {
        try
        {
            // 重建 XML 文档树
            XmlNode xmlRt = xmlDoc.SelectSingleNode("revolution");
            if (xmlRt == null)
            {
                xmlRt = xmlDoc.CreateNode(XmlNodeType.Element, "revolution", "");
                xmlDoc.AppendChild(xmlRt);
            }

            // 重建 Revolution/Config
            XmlNode xmlNd = xmlDoc.SelectSingleNode("revolution/config");
            if (xmlNd == null)
            {
                xmlNd = xmlDoc.CreateNode(XmlNodeType.Element, "config", "");
                xmlRt.AppendChild(xmlNd);
            }
            else
            {
                XmlNode ndd = xmlDoc.CreateNode(XmlNodeType.Element, "config", "");
                xmlRt.ReplaceChild(ndd, xmlNd);
                xmlNd = ndd;
            }
            //xmlNd.RemoveAll();

            // 重建 Revolution/Arrays
            XmlNode xmlArr = xmlDoc.SelectSingleNode("revolution/arrays");
            if (xmlArr == null)
            {
                xmlArr = xmlDoc.CreateNode(XmlNodeType.Element, "arrays", "");
                xmlRt.AppendChild(xmlArr);
            }
            else
            {
                XmlNode ndd = xmlDoc.CreateNode(XmlNodeType.Element, "arrays", "");
                xmlRt.ReplaceChild(ndd, xmlArr);
                xmlArr = ndd;
            }

            // 开始添加 add 节点
            foreach (string key in basicValues.Keys)
            {
                XmlNode nd = xmlDoc.CreateNode(XmlNodeType.Element, "add", "");

                nd.Attributes.Append(
                    xmlDoc.CreateAttribute("key")
                    );
                nd.Attributes.Append(
                    xmlDoc.CreateAttribute("value")
                    );
                nd.Attributes["key"].Value = key;
                nd.Attributes["value"].Value = _SafeGetString((string)basicValues[key]);

                xmlNd.AppendChild(nd);
            }

            // 开始添加 array 节点
            foreach (string key in arrayValues.Keys)
            {
                XmlNode nd = xmlDoc.CreateNode(XmlNodeType.Element, "array", "");
                string[] arr = (string[])arrayValues[key];

                nd.Attributes.Append(
                    xmlDoc.CreateAttribute("name")
                    );
                nd.Attributes["name"].Value = key;

                // Create the items
                foreach (string value in arr)
                {
                    XmlNode item = xmlDoc.CreateNode(XmlNodeType.Element, "item", "");

                    item.AppendChild(
                        xmlDoc.CreateTextNode(_SafeGetString(value))
                        );

                    nd.AppendChild(item);
                }

                // Replace or append
                xmlArr.AppendChild(nd);
            }

            // 保存 XML 文档
            xmlDoc.PreserveWhitespace = false;
            xmlDoc.Save(xmlPath);
        }
        catch (IOException ioex)
        {
            Debugger.LogException(ioex);
            throw new Exceptions.ConfigurationException("无法保存配置文件,原因可能是文件被占用,或者当前用户没有该权限。", ioex);
        }
        catch (Exception ex)
        {
            Debugger.LogException(ex);
            throw new Exceptions.ConfigurationException("因为未知错误,无法保存配置文件。", ex);
        }
    }

    private void loadConfig()
    {
        xmlDoc = new XmlDocument();

        try
        {
            // 打开 XML
            xmlDoc.Load(xmlPath);

            // 读取基本配置字段
            basicValues = new Hashtable();
            this.arrayValues = new Hashtable();

            XmlNodeList addValues = xmlDoc.SelectNodes("revolution/config/add");
            if (addValues != null && addValues.Count > 0)
            {
                foreach (XmlNode nd in addValues)
                {
                    string key, value;
                    key = nd.Attributes["key"] != null ? nd.Attributes["key"].Value : String.Empty;
                    value = nd.Attributes["value"] != null ? nd.Attributes["value"].Value : String.Empty;

                    if (!string.IsNullOrEmpty(key))
                    {
                        value = value != null ? value : String.Empty;
                        basicValues[key.ToLower()] = value;
                    }
                }
            }

            // 读取 Array 配置
            XmlNodeList arrayValues = xmlDoc.SelectNodes("revolution/arrays/array");
            if (arrayValues != null && arrayValues.Count > 0)
            {
                foreach (XmlNode arr in arrayValues)
                {
                    if (arr.Attributes["name"] == null
                        || string.IsNullOrEmpty(arr.Attributes["name"].Value))
                        continue;

                    List<string> strList = new List<string>();

                    // Pass through items
                    foreach (XmlNode item in arr.ChildNodes)
                    {
                        if (item.Name == "item"
                            && item.ChildNodes.Count > 0)
                        {
                            if (item.ChildNodes[0].NodeType == XmlNodeType.Text
                                || item.ChildNodes[0].NodeType == XmlNodeType.CDATA)
                                strList.Add(item.ChildNodes[0].Value);
                        }
                    }

                    // add to list
                    this.arrayValues[arr.Attributes["name"].Value.ToLower()] = strList.ToArray();
                }
            }
        }
        catch (IOException ioex)
        {
            Debugger.LogException(ioex);
            throw new Exceptions.ConfigurationException("无法读取配置文件,原因可能是文件被占用,或者当前用户没有该权限。", ioex);
        }
        catch (Exception ex)
        {
            Debugger.LogException(ex);
            throw new Exceptions.ConfigurationException("因为未知错误,无法读取配置文件。", ex);
        }
    }
}

 

为了在任何时间能够轻松访问配置文件,进一步可以这样处理:

 

/// <summary>
/// 快速访问特定程序内容的静态类。
/// </summary>
public static class App
{
    // 静态构造
    static App()
    {
        config = new Configuration(Path.Combine(Environment.CurrentDirectory, "config.xml"));
    }

    // 快速静态全局变量
    private static Configuration config;
    /// <summary>
    /// 读取配置文件对象。
    /// </summary>
    public static Configuration Config
    {
        get
        {
            return config;
        }
    }

    /// <summary>
    /// 提供重新定向配置文件的接口。
    /// </summary>
    /// <param name="configPath">。配置文件路径</param>
    public static void ReInit(string configPath)
    {
        config = new Configuration(configPath);
    }
}

这样就可以使用 App.Config 来访问我们的配置文件了。