zoukankan      html  css  js  c++  java
  • 读取和保存应用程序设置

    为了使我们的应用程序对用户友好,需要记住应用程序上次退出时的设置,以便再次运行这个应用程序恢复上次退出时的场景。

    在上面所示的应用程序中,“每章单词数”就是需要记住的应用程序设置。

    那么,让我们来写一个通用的抽象基类来做这件事吧。下面就是 AppConfigureBase.cs 源程序文件

    01:  using System;
    02:  using System.IO;
    03:  using System.Xml;
    04:  using System.Collections.Generic;
    05:  
    06:  namespace Skyiv.Common
    07:  {
    08:    /// <summary>
    09:    /// 用于读取和保存应用程序设置的抽象基类
    10:    /// </summary>
    11:    public abstract class AppConfigureBase
    12:    {
    13:      string configureFileName;
    14:      protected Dictionary<string, string> KeyValues;
    15:  
    16:      protected AppConfigureBase(string executeFileFullName)
    17:      {
    18:        configureFileName = Path.Combine(Path.GetDirectoryName(executeFileFullName),
    19:          Path.GetFileNameWithoutExtension(executeFileFullName) + ".xml");
    20:        KeyValues = new Dictionary<string, string>();
    21:        Load();
    22:      }
    23:  
    24:      void Load()
    25:      {
    26:        KeyValues.Clear();
    27:        try
    28:        {
    29:          var doc = new XmlDocument();
    30:          doc.Load(configureFileName);
    31:          foreach (XmlNode node in doc.DocumentElement.ChildNodes)
    32:            KeyValues.Add(node.Name, node.InnerText);
    33:        }
    34:        catch
    35:        {
    36:          // 当配置文件不存在时,不应该抛出异常。
    37:          // 此时,派生类应该使用缺省值进行配置。
    38:        }
    39:      }
    40:  
    41:      public void Save()
    42:      {
    43:        var doc = new XmlDocument();
    44:        doc.LoadXml(Api.XmlFileHeaderString + "<Settings />");
    45:        foreach (var kvp in KeyValues)
    46:        {
    47:          var elem = doc.CreateElement(kvp.Key);
    48:          elem.InnerText = kvp.Value;
    49:          doc.DocumentElement.AppendChild(elem);
    50:        }
    51:        doc.Save(configureFileName);
    52:      }
    53:  
    54:      protected string GetString(string key, string defaultValue)
    55:      {
    56:        string value;
    57:        if (!KeyValues.TryGetValue(key, out value)) return defaultValue;
    58:        return value;
    59:      }
    60:  
    61:      protected void SetString(string key, string value)
    62:      {
    63:        KeyValues[key] = value;
    64:      }
    65:  
    66:      protected long GetInt64(string key, long defalutValue)
    67:      {
    68:        return long.Parse(GetString(key, defalutValue.ToString()));
    69:      }
    70:  
    71:      protected void SetInt64(string key, long value)
    72:      {
    73:        SetString(key, value.ToString());
    74:      }
    75:  
    76:      protected DateTime GetDateTime(string key, DateTime defaultValue)
    77:      {
    78:        return DateTime.FromBinary(GetInt64(key, defaultValue.ToBinary()));
    79:      }
    80:  
    81:      protected void SetDateTime(string key, DateTime value)
    82:      {
    83:        SetInt64(key, value.ToBinary());
    84:      }
    85:    }
    86:  }

    上述程序中第 54 行到第 84 行的 GetXXX 和 SetXXX 方法被声明为 protected,供派生类使用。如有需要,可自行增加获取和设置不同数据类型的方法。

    哦,上述程序第 44 行中用到的 Api 类所在的 Api.cs 源程序文件如下所示:

    01:  using System.Text;
    02:  
    03:  namespace Skyiv.Common
    04:  {
    05:    /// <summary>
    06:    /// 一些通用的东东
    07:    /// </summary>
    08:    public static class Api
    09:    {
    10:      public static string XmlFileHeaderString = @"<?xml version=""1.0"" encoding=""UTF-8""?>";
    11:      public static readonly Encoding GB18030Encoding = Encoding.GetEncoding("GB18030");
    12:    }
    13:  }

    我们的应用程序应该从 AppConfigureBase 这个抽象基类派生出自己的应用程序配置类,例如下面的 AppConfigure.cs:

    01:  using Skyiv.Common;
    02:  
    03:  namespace Skyiv.PowerWord2Snb
    04:  {
    05:    /// <summary>
    06:    /// 应用程序设置
    07:    /// </summary>
    08:    sealed class AppConfigure : AppConfigureBase
    09:    {
    10:      static readonly string WordsPerChapterString = "WordsPerChapter";
    11:  
    12:      public AppConfigure(string executeFileFullName)
    13:        : base(executeFileFullName)
    14:      {
    15:      }
    16:  
    17:      /// <summary>
    18:      /// 每章单词数
    19:      /// </summary>
    20:      public long WordsPerChapter
    21:      {
    22:        get { return GetInt64(WordsPerChapterString, 20); }
    23:        set { SetInt64(WordsPerChapterString, value); }
    24:      }
    25:    }
    26:  }

    下面就是用于保存应用程序设置的 PowerWord2Snb.xml 文件:

    1:  <?xml version="1.0" encoding="UTF-8"?>
    2:  <Settings>
    3:    <WordsPerChapter>20</WordsPerChapter>
    4:  </Settings>

    注意,如果我们的应用程序运行时还不存在这个 XML 文件,不应该报错,而是应该使用的缺省值进行配置。然后在退出应用程序时生成一个 XML 文件来保存应用程序的设置。

    下面就是应用程序主窗体对应的 MainForm 类所在的 MainForm.cs 源程序文件中和应用程序设置相关的内容:

    01:  namespace Skyiv.PowerWord2Snb
    02:  {
    03:    public partial class MainForm : Form
    04:    {
    05:      AppConfigure appConfigure;
    06:  
    07:      private void MainForm_Load(object sender, EventArgs e)
    08:      {
    09:        appConfigure = new AppConfigure(assembly.ExecuteFileFullName);
    10:        nudWordsPerChapter.Value = appConfigure.WordsPerChapter;
    11:      }
    12:  
    13:      private void MainForm_FormClosed(object sender, FormClosedEventArgs e)
    14:      {
    15:        appConfigure.WordsPerChapter = (long)nudWordsPerChapter.Value;
    16:        appConfigure.Save();
    17:      }
    18:    }
    19:  }

    在上述源程序中,在应用程序主窗体装入时,初始化一个 AppConfigure 类的实例,然后再用其 WordsPerChapter 属性来设置主窗体中的 NumericUpDown 控件的值。最后,用户退出应用程序时,引发 FormClosed 事件,在这个事件处理程序中将 NumericUpDown 控件的值赋给 AppConfigure 类的 WordsPerChapter 属性,接着调用 AppConfigureBase 类的 Save 方法将应用程序的设置写入 XML 文件。

    就这么简单。 微笑

    我们已经看到了一个 GUI 界面的应用程序的例子。好吧,我们再来一个 CUI 界面的应用程序,演示稍微复杂一点的应用程序设置,这次的设置包括一个字符串、一个日期、一个整数。下面就是 AppConfigureTester.cs:

    01:  using System;
    02:  
    03:  namespace Skyiv.Tester
    04:  {
    05:    class AppConfigureTester
    06:    {
    07:      static void Main()
    08:      {
    09:        try
    10:        {
    11:          var app = new AppConfigureTester();
    12:          var cfg = new AppConfigure("AppConfigureTester.exe");
    13:          app.Show(cfg);                        // 显示应用程序本次运行的设置
    14:          cfg.Count += 1;                       // 每次运行增加一块金币
    15:          cfg.Birth = new DateTime(1997, 7, 1); // 设置出生日期
    16:          cfg.Save();                           // 退出之前保存应用程序设置
    17:        }
    18:        catch (Exception ex)
    19:        {
    20:          Console.WriteLine(ex.Message);
    21:        }
    22:      }
    23:  
    24:      void Show(AppConfigure cfg)
    25:      {
    26:        Console.WriteLine("姓名: " + cfg.Name);
    27:        Console.WriteLine("出生: " + cfg.Birth.ToString("ddddd yyyy-MM-dd HH:mm:ss"));
    28:        Console.WriteLine("金币: " + cfg.Count);
    29:      }
    30:    }
    31:  }

    相应的 AppConfigure.cs 如下所示:

    01:  using System;
    02:  using Skyiv.Common;
    03:  
    04:  namespace Skyiv.Tester
    05:  {
    06:    /// <summary>
    07:    /// 应用程序设置
    08:    /// </summary>
    09:    sealed class AppConfigure : AppConfigureBase
    10:    {
    11:      static readonly string NameString = "Name";
    12:      static readonly string BirthString = "Birth";
    13:      static readonly string CountString = "Count";
    14:  
    15:      public AppConfigure(string executeFileFullName)
    16:        : base(executeFileFullName)
    17:      {
    18:      }
    19:  
    20:      public string Name
    21:      {
    22:        get { return GetString(NameString, "无名氏"); }
    23:        set { SetString(NameString, value); }
    24:      }
    25:  
    26:      public DateTime Birth
    27:      {
    28:        get { return GetDateTime(BirthString, DateTime.Now); }
    29:        set { SetDateTime(BirthString, value); }
    30:      }
    31:  
    32:      public long Count
    33:      {
    34:        get { return GetInt64(CountString, 20); }
    35:        set { SetInt64(CountString, value); }
    36:      }
    37:    }
    38:  }

    该 CUI 程序第一次运行的结果如下所示:

    姓名: 无名氏
    出生: 星期一 2010-12-27 00:03:11
    金币: 20
    

    这是因为此时还没有保存应用程序设置的 XML 文件,因此就采用了缺省值,姓名是“无名氏”,出生日期是现在的时间,金币数量为20。

    再次运行,结果如下所示:

    姓名: 无名氏
    出生: 星期二 1997-07-01 00:00:00
    金币: 21
    

    可以看出,姓名不变,出生日期在 AppConfigureTester.cs 第 15 行中设置为1997年7月1日。金币数量在第 14 行中增加了一块,变为21了。

    检查一下 AppConfigureTester.xml 文件,如下所示:

    1:  <?xml version="1.0" encoding="UTF-8"?>
    2:  <Settings>
    3:    <Count>22</Count>
    4:    <Birth>630033120000000000</Birth>
    5:  </Settings>

    这个文件中第 3 行的 22 说明下次运行时金币数量将增加到 22 块。第 44 行的这个很大的整数是1997年7月1日这个日期在 DateTime 结构的内部表示。而姓名一直没有修改过,所以没有保存到 XML 文件中,应用程序的每次运行都将使用缺省值“无名氏”。

  • 相关阅读:
    迭代模型
    螺旋模型
    瀑布模型
    V模型
    codeforces411div.2
    专题1:记忆化搜索/DAG问题/基础动态规划
    Python
    字符串的相关操作方法
    Python基本数据类型
    编码
  • 原文地址:https://www.cnblogs.com/bingyun84/p/1931016.html
Copyright © 2011-2022 走看看