为.NET应用程序存储用户设置的最佳方式是什么?

我有一个.NET 2.0 Windows窗体应用程序。 商店用户设置的最佳位置在哪里(考虑Windows指南)?

有些人指向Application.LocalUserAppDataPath 。 但是,这会创build一个文件夹结构,如:

C:\ Documents and Settings \ user_name \ Local Settings \ Application Data \ company_name \ product_name \ product_version \

如果我发布我的应用程序的版本1,并在那里存储一个XML文件,然后发布版本2,这将更改为不同的文件夹,对不对? 无论应用程序版本如何,我都希望每个用户都有一个文件夹来存储设置。

我喜欢使用内置的应用程序设置 。 然后,如果您想在devise时或运行时使用设置devise器,则可以使用以下内容:

 // read setting string setting1 = (string)Settings.Default["MySetting1"]; // save setting Settings.Default["MySetting2"] = "My Setting Value"; // you can force a save with Properties.Settings.Default.Save(); 

它会将设置存储在您描述的类似文件夹结构中(使用path中的版本)。 但是,只需简单地调用:

 Properties.Settings.Default.Upgrade(); 

该应用程序将拉动所有以前的版本设置保存在。

.NET应用程序具有易于使用的内置设置机制。 在我看来,问题在于它将这些设置存储在一个相当模糊的目录中,最终用户将无法find它。 而且,只是从debugging切换到发布版本会改变这个目录的位置,这意味着保存在一个configuration中的任何设置都会在另一个configuration中丢失。

由于这些和其他原因,我想出了我自己的Windows窗体的设置代码 。 它不像.NET中的那么光滑,但它更加灵活,我一直都在使用它。

或者将您的设置写入xml文件并使用“ 隔离存储”进行保存 。 根据您使用的商店,将其保存在“应用程序数据”文件夹中。 您也可以select启用漫游的商店,这意味着当用户login不同的计算机时,设置随之一起移动。

过去曾经为我工作过的一种方法是创build一个设置类并使用XML序列化将其写入文件系统。 你可以通过创build一个设置对象集合并序列化来扩展这个概念。 您可以在一个位置为所有用户提供所有设置,而无需担心pipe理文件系统。

在任何人给我任何部分重新发明方向盘之前,让我说一些事情。 首先,只有几行代码才能序列化和写入文件。 其次,如果你有一个包含你的设置的对象,当你加载你的应用程序时,你不必多次调用appSettings对象。 最后,添加代表您的应用程序状态的项目非常简单,从而允许您在下次加载应用程序时恢复长时间运行的任务。

设置是标准键值对(stringstring)。 如果有帮助,我可以把它们包装在一个XML文件中。

我宁愿使用文件系统,而不是registry。 这似乎更容易维护。 在支持情况下,如果用户需要手动打开/更改设置,那么如果它在文件系统中会更容易。

我尝试一些方法来存储我的设置,以简单的文本文件,我发现最好的方式:

文件存储在应用程序文件夹中,以用法, settings.txt :(在设置文件批准的意见,尝试/ /评论)

//获取设置值

 Settings.Get("name", "Ivan"); 

//设置设置值

 Settings.Set("name", "John"); 

使用:

 using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; 

//你也可以用section名称来存储,只需要添加name section(section_name,name,value)和Get(section_name,name,value)

 public static class Settings { private static string SECTION = typeof(Settings).Namespace;//"SETTINGS"; private static string settingsPath = Application.StartupPath.ToString() + "\\settings.txt"; [DllImport("kernel32")] private static extern long WritePrivateProfileString(string section, string key, string val, string filePath); [DllImport("kernel32")] private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath); public static String GetString(String name) { StringBuilder temp = new StringBuilder(255); int i = GetPrivateProfileString(SECTION,name,"",temp,255,settingsPath); return temp.ToString(); } public static String Get(String name, String defVal) { return Get(SECTION,name,defVal); } public static String Get(string _SECTION, String name, String defVal) { StringBuilder temp = new StringBuilder(255); int i = GetPrivateProfileString(_SECTION, name, "", temp, 255, settingsPath); return temp.ToString(); } public static Boolean Get(String name, Boolean defVal) { return Get(SECTION, name, defVal); } public static Boolean Get(string _SECTION, String name, Boolean defVal) { StringBuilder temp = new StringBuilder(255); int i = GetPrivateProfileString(_SECTION,name,"",temp,255,settingsPath); bool retval=false; if (bool.TryParse(temp.ToString(),out retval)) { return retval; } else { return retval; } } public static int Get(String name, int defVal) { return Get(SECTION, name, defVal); } public static int Get(string _SECTION, String name, int defVal) { StringBuilder temp = new StringBuilder(255); int i = GetPrivateProfileString(SECTION,name,"",temp,255,settingsPath); int retval=0; if (int.TryParse(temp.ToString(),out retval)) { return retval; } else { return retval; } } public static void Set(String name, String val) { Set(SECTION, name,val); } public static void Set(string _SECTION, String name, String val) { WritePrivateProfileString(_SECTION, name, val, settingsPath); } public static void Set(String name, Boolean val) { Set(SECTION, name, val); } public static void Set(string _SECTION, String name, Boolean val) { WritePrivateProfileString(_SECTION, name, val.ToString(), settingsPath); } public static void Set(String name, int val) { Set(SECTION, name, val); } public static void Set(string _SECTION,String name, int val) { WritePrivateProfileString(SECTION, name, val.ToString(), settingsPath); } } 

独立存储主要用于使用ClickOnce分发的应用程序 ,并在安全沙箱中运行。 基本path是为你决定的,你将无法在你的代码中推论出它。 path将会像“\ LocalSettings \ ApplicationData \ IsolatedStorage \ ejwnwe.302 \ kfiwemqi.owx \ url.asdaiojwejoieajae ….”,并不是那么友善。 您的存储空间也是有限的。

瑞安·法利(Ryan Farley)是对的 。

除了产品版本之外,我还会下载您发布的文件夹列表。 更新发布后,您不希望设置重置。

由于debugging/占用空间的因素,我实际上正在远离用户设置的registry。 我目前只在registry中存储了几个基本设置(窗口大小,位置,数据文件的版本),如果更新失败或用户丢失了第二台显示器,我遇到了更多的问题应用程序正在开放。 他们中的一些人精通理解registry,但其余的他们必须重新安装,这很快,但我认为他们发牢骚了一下。 随着基于文件的版本,我所要做的就是让他们在记事本中打开一个XML文件,并做一个快速的调整。

此外,我正在寻找使我的应用程序可以从USB闪存驱动器运行,并将设置绑定到文件似乎更友好的过程。 我敢肯定,我可以做一些代码来检查/清理registry,但我认为我们大多数人已经厌倦了registry混乱,似乎现在我们的机器吃掉了。

我知道这里有一些安全的权衡,但是我所sorting的数据中没有一个对于这个原因是至关重要的,而且由于应用程序的规模,我没有遭受任何性能冲击。