我想要实现的非常简单:我有一个Windows窗体(。NET 3.5)应用程序使用路径来读取信息。用户可以使用我提供的选项表单修改此路径。

现在,我想将路径值保存到一个文件中以供以后使用。这将是保存到该文件中的众多设置之一。该文件将直接位于应用程序文件夹中。

我知道有三种选择:

配置文件(appname.exe.config) 注册表 自定义XML文件

我读到。net配置文件不能将值保存回配置文件。至于注册表,我想尽量远离它。

这是否意味着我应该使用自定义XML文件来保存配置设置?

如果是这样,我想看看代码的例子(c#)。

我看过其他关于这个问题的讨论,但我仍然不清楚。


当前回答

有时你想要去掉传统网络中保留的那些设置。Config或app.config文件。您希望对设置项的部署和分离的数据设计进行更细粒度的控制。或者需求是支持在运行时添加新条目。

我可以想到两个好的选择:

强类型版本和 面向对象版本。

强类型版本的优点是强类型设置名称和值。没有混合名称或数据类型的风险。缺点是更多的设置必须被编码,不能在运行时添加。

使用面向对象版本的优点是可以在运行时添加新的设置。但是您没有强类型的名称和值。必须小心使用字符串标识符。获取值时必须知道之前保存的数据类型。

您可以在这里找到这两个全功能实现的代码。

其他回答

登记处是不允许的。您不确定使用您的应用程序的用户是否有足够的权限写入注册表。

您可以使用app.config文件保存应用程序级别的设置(对于使用您的应用程序的每个用户都是相同的)。

我将把特定于用户的设置存储在一个XML文件中,该文件将保存在隔离存储或SpecialFolder中。ApplicationData目录。

其次,从。net 2.0开始,可以将值存储回app.config文件。

如果你打算保存到与你的可执行文件相同目录下的文件,这里有一个使用JSON格式的很好的解决方案:

using System;
using System.IO;
using System.Web.Script.Serialization;

namespace MiscConsole
{
    class Program
    {
        static void Main(string[] args)
        {
            MySettings settings = MySettings.Load();
            Console.WriteLine("Current value of 'myInteger': " + settings.myInteger);
            Console.WriteLine("Incrementing 'myInteger'...");
            settings.myInteger++;
            Console.WriteLine("Saving settings...");
            settings.Save();
            Console.WriteLine("Done.");
            Console.ReadKey();
        }

        class MySettings : AppSettings<MySettings>
        {
            public string myString = "Hello World";
            public int myInteger = 1;
        }
    }

    public class AppSettings<T> where T : new()
    {
        private const string DEFAULT_FILENAME = "settings.json";

        public void Save(string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(this));
        }

        public static void Save(T pSettings, string fileName = DEFAULT_FILENAME)
        {
            File.WriteAllText(fileName, (new JavaScriptSerializer()).Serialize(pSettings));
        }

        public static T Load(string fileName = DEFAULT_FILENAME)
        {
            T t = new T();
            if(File.Exists(fileName))
                t = (new JavaScriptSerializer()).Deserialize<T>(File.ReadAllText(fileName));
            return t;
        }
    }
}
public static class SettingsExtensions
{
    public static bool TryGetValue<T>(this Settings settings, string key, out T value)
    {
        if (settings.Properties[key] != null)
        {
            value = (T) settings[key];
            return true;
        }

        value = default(T);
        return false;
    }

    public static bool ContainsKey(this Settings settings, string key)
    {
        return settings.Properties[key] != null;
    }

    public static void SetValue<T>(this Settings settings, string key, T value)
    {
        if (settings.Properties[key] == null)
        {
            var p = new SettingsProperty(key)
            {
                PropertyType = typeof(T),
                Provider = settings.Providers["LocalFileSettingsProvider"],
                SerializeAs = SettingsSerializeAs.Xml
            };
            p.Attributes.Add(typeof(UserScopedSettingAttribute), new UserScopedSettingAttribute());
            var v = new SettingsPropertyValue(p);
            settings.Properties.Add(p);
            settings.Reload();
        }
        settings[key] = value;
        settings.Save();
    }
}

其他选项,除了使用自定义XML文件,我们还可以使用更用户友好的文件格式:JSON或YAML文件。

如果你使用。net 4.0动态,这个库真的很容易使用 (序列化,反序列化,嵌套对象支持和排序输出 +将多个设置合并为一个)JsonConfig(使用相当于ApplicationSettingsBase) .NET YAML配置库…我还没找到一个 易于作为JsonConfig使用

您可以将您的设置文件存储在多个特殊的文件夹中(针对所有用户和每个用户),如环境所列。SpecialFolder枚举和多个文件(默认为只读,每个角色,每个用户,等等)

获取特殊文件夹路径的示例 % AppData %

如果需要使用多个设置,可以将这些设置合并:例如“default + BasicUser + AdminUser”的设置合并。您可以使用自己的规则:最后一个规则覆盖值,等等。

一种简单的方法是使用配置数据对象,将其保存为本地文件夹中具有应用程序名称的XML文件,并在启动时读取它。

下面是存储表单位置和大小的示例。

配置数据对象是强类型的,易于使用:

[Serializable()]
public class CConfigDO
{
    private System.Drawing.Point m_oStartPos;
    private System.Drawing.Size m_oStartSize;

    public System.Drawing.Point StartPos
    {
        get { return m_oStartPos; }
        set { m_oStartPos = value; }
    }

    public System.Drawing.Size StartSize
    {
        get { return m_oStartSize; }
        set { m_oStartSize = value; }
    }
}

用于保存和加载的管理器类:

public class CConfigMng
{
    private string m_sConfigFileName = System.IO.Path.GetFileNameWithoutExtension(System.Windows.Forms.Application.ExecutablePath) + ".xml";
    private CConfigDO m_oConfig = new CConfigDO();

    public CConfigDO Config
    {
        get { return m_oConfig; }
        set { m_oConfig = value; }
    }

    // Load configuration file
    public void LoadConfig()
    {
        if (System.IO.File.Exists(m_sConfigFileName))
        {
            System.IO.StreamReader srReader = System.IO.File.OpenText(m_sConfigFileName);
            Type tType = m_oConfig.GetType();
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            object oData = xsSerializer.Deserialize(srReader);
            m_oConfig = (CConfigDO)oData;
            srReader.Close();
        }
    }

    // Save configuration file
    public void SaveConfig()
    {
        System.IO.StreamWriter swWriter = System.IO.File.CreateText(m_sConfigFileName);
        Type tType = m_oConfig.GetType();
        if (tType.IsSerializable)
        {
            System.Xml.Serialization.XmlSerializer xsSerializer = new System.Xml.Serialization.XmlSerializer(tType);
            xsSerializer.Serialize(swWriter, m_oConfig);
            swWriter.Close();
        }
    }
}

现在你可以创建一个实例,并在你的表单的加载和关闭事件中使用:

    private CConfigMng oConfigMng = new CConfigMng();

    private void Form1_Load(object sender, EventArgs e)
    {
        // Load configuration
        oConfigMng.LoadConfig();
        if (oConfigMng.Config.StartPos.X != 0 || oConfigMng.Config.StartPos.Y != 0)
        {
            Location = oConfigMng.Config.StartPos;
            Size = oConfigMng.Config.StartSize;
        }
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        // Save configuration
        oConfigMng.Config.StartPos = Location;
        oConfigMng.Config.StartSize = Size;
        oConfigMng.SaveConfig();
    }

生成的XML文件也是可读的:

<?xml version="1.0" encoding="utf-8"?>
<CConfigDO xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <StartPos>
    <X>70</X>
    <Y>278</Y>
  </StartPos>
  <StartSize>
    <Width>253</Width>
    <Height>229</Height>
  </StartSize>
</CConfigDO>