为 .NET 应用程序存储用户设置的最佳方式是啥?
Posted
技术标签:
【中文标题】为 .NET 应用程序存储用户设置的最佳方式是啥?【英文标题】:What is the best way to store user settings for a .NET application?为 .NET 应用程序存储用户设置的最佳方式是什么? 【发布时间】:2010-09-06 18:48:10 【问题描述】:我有一个 .NET 2.0 Windows 窗体应用程序。商店用户设置的最佳位置在哪里(考虑 Windows 指南)?
有人指向Application.LocalUserAppDataPath
。但是,这会创建一个文件夹结构,例如:
C:\Documents and Settings\user_name\Local Settings\Application 数据\公司名称\产品名称\产品版本\
如果我发布我的应用程序的版本 1 并在其中存储一个 XML 文件,然后发布版本 2,那将更改为不同的文件夹,对吗?无论应用程序版本如何,我都希望每个用户都有一个文件夹来存储设置。
【问题讨论】:
我认为this article 涵盖了解决方案。 Updated link 来自 Jorges 评论。 【参考方案1】:我喜欢使用内置的Application Settings。然后,如果您想在设计时或运行时使用设置设计器,那么您已经内置了支持:
// 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();
它确实将设置存储在与您描述的类似的文件夹结构中(路径中包含版本)。但是,只需简单调用:
Properties.Settings.Default.Upgrade();
该应用程序将拉入所有以前的版本设置以保存。
【讨论】:
Settings.Default
唯一令人讨厌的地方是您需要事先手动创建它们,这与 Cocoa 中的 NSUserDefaults
不同,如果设置不存在则返回 nil。
这是在哪个命名空间中?我似乎无法访问我的 .NET 4 winforms 应用程序中的设置对象。
Properties.Settings.Default
瑞恩·法利。如何在多用户环境中使用上述设置
@Anjali 设置存储在用户特定的文件夹中,因此多用户环境中的每个用户都将根据自己的用户环境拥有自己的设置文件。除非您询问如何让他们共享设置,否则不能这样做。【参考方案2】:
.NET 应用程序具有易于使用的内置设置机制。在我看来,它的问题在于它将这些设置存储到一个相当模糊的目录中,最终用户将无法找到它。此外,只是从调试版本切换到发布版本会更改此目录的位置,这意味着保存在一个配置中的任何设置都会丢失在另一个配置中。
出于这些和其他原因,我想出了my own settings code for Windows Forms。它不像 .NET 附带的那样流畅,但更灵活,我一直都在使用它。
【讨论】:
【参考方案3】:或者将您的设置写入 xml 文件并使用Isolated Storage 保存。根据您使用的商店,它会将其保存在 Application Data 文件夹中。您还可以选择启用漫游的存储,这意味着当用户登录另一台计算机时,设置会随之移动。
【讨论】:
【参考方案4】:过去对我有用的一种方法是创建一个设置类并使用 XML 序列化将其写入文件系统。您可以通过创建一组设置对象并将其序列化来扩展此概念。您可以将所有用户的所有设置集中在一个地方,而不必担心管理文件系统。
在有人批评我部分重新发明***之前,让我先说几句。其一,序列化和写入文件只需几行代码。其次,如果您有一个包含您的设置的对象,则在加载应用程序时不必多次调用 appSettings 对象。最后,添加代表应用程序状态的项目非常容易,从而允许您在应用程序下次加载时恢复长时间运行的任务。
【讨论】:
如果您愿意构建自定义 XML 序列化,为什么不将其序列化为单个应用程序设置?这样您就可以使用应用程序设置基础架构。创建一个可序列化的类或类型转换器,然后使用应用设置对话框导入该类。【参考方案5】:我尝试了一些方法将我的设置存储到简单的文本文件中,我找到了最好的方法:
存储在应用程序文件夹中的文件,用于使用,settings.txt: (在设置文件中批准 cmets,尝试 //comment)
//获取设置值
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;
//你也可以用段名存储,使用只需添加名称段Set(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);
【讨论】:
【参考方案6】:设置是标准的键值对(字符串-字符串)。如果有帮助,我可以将它们包装在一个 XML 文件中。
我宁愿使用文件系统而不是注册表。它似乎更容易维护。在支持场景中,如果用户需要手动打开/更改设置,如果它在文件系统中会更容易。
【讨论】:
【参考方案7】:隔离存储主要用于使用ClickOnce 分发的应用程序,并在安全沙箱中运行。基本路径是为您决定的,您将无法在代码中推断它。路径类似于“\LocalSettings\ApplicationData\IsolatedStorage\ejwnwe.302\kfiwemqi.owx\url.asdaiojwejoieajae....”,并不是那么友好。您的存储空间也有限。
Ryan Farley has it right.
【讨论】:
【参考方案8】:除了产品版本之外,我会查看您发布的文件夹列表。您不希望在发布更新后重置设置。
由于调试/占用空间因素,我实际上正在远离用户设置的注册表。我目前只在注册表中存储了一些基本设置(窗口大小、位置、数据文件的版本),如果更新出错或用户丢失第二台显示器,我会遇到更多问题,这就是该应用程序正在打开。他们中的一些人足够精明,可以理解 regedit,但对于其余的人来说,他们必须重新安装,这很快,但我认为他们有点抱怨。对于基于文件的版本,我所要做的就是让他们在记事本中打开一个 XML 文件并进行快速调整。
此外,我希望让我的应用程序可以在 USB 闪存驱动器上运行,并且将设置绑定到文件中似乎对这个过程更友好。我确信我可以编写一些代码来检查/清理注册表,但我认为我们中的大多数人已经厌倦了如今似乎吞噬我们机器的注册表混乱。
我知道对此进行了一些安全权衡,但我正在排序的所有数据都不是对此至关重要的,而且由于应用程序的大小,我没有遭受任何性能损失。
【讨论】:
以上是关于为 .NET 应用程序存储用户设置的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在 Win32 Delphi 应用程序中存储用户首选项和设置的最佳实践是啥?