如何在 Windows 窗体应用程序中保存应用程序设置?

How can I save application settings in a Windows Forms application?

提问人:Fueled 提问时间:1/17/2009 最后编辑:Peter MortensenFueled 更新时间:5/24/2022 访问量:546732

问:

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

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

我知道有三个选项可用:

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

我读到.NET配置文件不会被预见到将值保存回它。至于注册表,我想尽可能远离它。

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

如果是这样,我想看看它的代码示例(C#)。

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

C# XML WinForms 配置文件 应用程序设置

评论

1赞 Portman 1/17/2009
这是 .NET WinForms 应用程序吗?如果是这样,您正在开发哪个版本的 .NET?
2赞 Fueled 1/17/2009
是的,它是 .NET Framework 3.5 版 WinForms 应用程序。
1赞 Kiquenet 9/21/2015
您是否需要保存密码或机密值?可能需要任何加密

答:

71赞 Frederik Gheysels 1/17/2009 #1

注册表是不行的。您不确定使用您的应用程序的用户是否具有足够的权限来写入注册表。

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

我会将特定于用户的设置存储在 XML 文件中,该文件将保存在独立存储SpecialFolder.ApplicationData 目录中。

除此之外,从 .NET 2.0 开始,可以将值存储回文件中。app.config

评论

9赞 1/17/2009
但是,如果您需要每个登录名/用户的设置,请使用注册表。
11赞 Kenny Mann 9/10/2009
@thenonhacker:或使用 Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
4赞 deegee 6/29/2013
@thenonhacker - 注册表不是必需的,也不应用于存储应用程序设置 - 永远。System.Environment.SpecialFolder.LocalApplicationData 是每用户的本地文件夹。这。ApplicationData 是每用户漫游文件夹。查看 msdn.microsoft.com/en-us/library/...
6赞 Kesty 2/17/2017
可以写入用户注册表(许多程序在那里写入信息,用户权限从来都不是问题)。与使用设置相比,使用注册表的优点是,如果多个应用程序共享同一文件夹(例如,安装程序和应用程序),则它们不会共享相同的设置。
5赞 i486 10/20/2017
注册表的主要缺点是很难将设置导出/复制到其他 PC。但我不同意“您不确定使用您的应用程序的用户是否有足够的权限写入注册表”——HKEY_CURRENT_USER您始终有权写入。它可以被拒绝,但当前用户也可以访问文件系统(所有可能的 TEMP 文件夹等)。
4赞 Jacob 1/17/2009 #2

据我所知,.NET 确实支持使用内置应用程序设置工具进行持久化设置:

使用 Windows 窗体的“应用程序设置”功能,可以轻松地在客户端计算机上创建、存储和维护自定义应用程序和用户首选项。使用 Windows 窗体应用程序设置,您不仅可以存储应用程序数据(如数据库连接字符串),还可以存储特定于用户的数据(如用户应用程序首选项)。使用 Visual Studio 或自定义托管代码,可以创建新设置,从中读取设置并将其写入磁盘,将它们绑定到窗体上的属性,并在加载和保存之前验证设置数据。 - http://msdn.microsoft.com/en-us/library/k4s6c3a0.aspx

评论

2赞 Gishu 1/17/2009
不对。.请参阅上面 Aku 的回答。可以使用 Settings 和 ApplicationSettingsBase
662赞 aku 1/17/2009 #3

如果使用 Visual Studio,则很容易获得持久性设置。右键单击“解决方案资源管理器”中的项目,然后选择“属性”。选择“设置”选项卡,然后单击超链接(如果设置不存在)。

使用“设置”选项卡创建应用程序设置。Visual Studio 创建文件,其中包含从 ApplicationSettingsBase 继承的单一实例类。可以从代码访问此类以读取/写入应用程序设置:Settings.settingsSettings.Designer.settingsSettings

Properties.Settings.Default["SomeProperty"] = "Some Value";
Properties.Settings.Default.Save(); // Saves settings in application configuration file

此方法适用于控制台、Windows 窗体和其他项目类型。

请注意,您需要设置设置的 scope 属性。如果选择“应用程序范围”,则 Settings.Default.<your property> 将是只读的。

参考:如何:使用 C# 在运行时编写用户设置 - Microsoft 文档

评论

2赞 franko_camron 10/28/2011
如果我有解决方案,这适用于整个解决方案还是每个项目?
9赞 doekman 1/16/2012
@Four:我这里有一个 .NET 4.0 WinApp 项目,我的 SomeProperty 不是只读的。 就像一个魅力。还是因为我有用户设置?Settings.Default.SomeProperty = 'value'; Settings.Default.Save();
4赞 doekman 1/17/2012
@Four:当我将设置从“用户”更改为“应用程序范围”并保存文件时,我在生成的代码中看到 setter 消失了。客户端配置文件 4.0 也会发生这种情况......
3赞 minnow 9/14/2012
@Four:很棒的链接,尽管你什么都不做的说法是不正确的。正如@aku在答案中所述,应用范围的设置是只读的:保存对它们无效。使用该自定义 PortableSettingsProvider 将用户范围设置保存到位于 exe 所在的 app.config 中,而不是用户的 AppData 文件夹中的设置。不,通常不是很好,但我在开发过程中使用它来使用从编译到编译的相同设置(没有它,它们在每次编译时都会进入新的唯一用户文件夹)。Settings.Default.Save()
8赞 eselk 6/18/2013
截至目前,在 .NET 3.5 中,您似乎只能使用 Settings.Default.SomeProperty 来分配值并获得强类型转换。此外,为了节省其他人的时间(我花了一段时间才弄清楚这一点),您需要键入 Properties.Settings.Default,或将 using YourProjectNameSpace.Settings 添加到文件顶部。无法单独定义/找到“设置”。
21赞 Hans Passant 1/17/2009 #4

该类不支持将设置保存到 app.config 文件。这在很大程度上是设计使然;使用适当保护的用户帐户(例如Vista UAC)运行的应用程序没有对程序安装文件夹的写入权限。ApplicationSettings

你可以用班级来对抗系统。但简单的解决方法是进入设置设计器并将设置的范围更改为“用户”。如果这会导致困难(例如,该设置与每个用户相关),则应将“选项”功能放在单独的程序中,以便可以请求权限提升提示。或者放弃使用设置。ConfigurationManager

评论

0赞 CannibalSmith 11/6/2009
你能详细解释一下你的最后一句话吗?请求提升以编写 app.config 或编写一个单独的应用程序来遍历所有用户的主页,查找 user.config 并编辑这些?
2赞 Hans Passant 11/6/2009
单独的程序需要清单来请求提升。Google 'asinvoker requireadministrator' 以找到正确的语法。编辑 user.config 是不切实际的,也没有必要。
8赞 gatapia 9/10/2009 #5

我不喜欢建议的使用 or 的解决方案。尝试阅读您自己的 XML。查看 XML 设置文件 – 不再有 web.configweb.configapp.config

104赞 Trevor 7/1/2011 #6

如果您打算保存到与可执行文件相同的目录中的文件,这里有一个使用 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;
        }
    }
}

评论

1赞 Jesse Chisholm 4/21/2015
无需更改,只需致电;全部大写,应该是一个常数。如果需要读写属性,请创建一个属性,并让构造函数将其设置为 。然后,将默认参数值设为 ,为此进行测试,并使用您的属性作为默认值。它打字多了一点,但给你一个更标准的界面。DEFAULT_FILENAMEsettings.Save(theFileToSaveTo)DEFAULT_FILENAMEDEFAULT_FILENAMEnull
11赞 TEK 3/31/2016
如果尚未参考,则需要参考。System.Web.Extensions.dll
11赞 NucS 12/18/2017
我基于这个答案创建了一个完整的库,并进行了许多改进,并在 nuget 中提供了它: github.com/Nucs/JsonSettings
2赞 Andy 12/19/2020
不要写入与 exe 相同的文件夹,除非您正在开发一个您知道只会安装到 appdata 的应用程序。如果您的 exe 安装到任一程序文件夹,则用户极不可能将文件保存在那里。为什么不呢?事实证明,允许应用程序将文件保存到存储 dll 和 exe 的位置是一个安全漏洞。
1赞 yo3hcv 10/5/2021
特雷弗,这真是非常简单可靠的解决方案!我能够立即保存我的复杂对象......使用 XML,我会花几天时间让它工作。再次感谢!
18赞 Boczek 10/11/2011 #7

registry/configurationSettings/XML 参数似乎仍然非常活跃。随着技术的进步,我都用过了,但我最喜欢的是基于 Threed 的系统隔离存储相结合。

下面的示例允许将名为 properties 的对象存储到独立存储中的文件中。如:

AppSettings.Save(myobject, "Prop1,Prop2", "myFile.jsn");

可以使用以下方法恢复属性:

AppSettings.Load(myobject, "myFile.jsn");

它只是一个示例,并不建议最佳实践。

internal static class AppSettings
{
    internal static void Save(object src, string targ, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = src.GetType();

        string[] paramList = targ.Split(new char[] { ',' });
        foreach (string paramName in paramList)
            items.Add(paramName, type.GetProperty(paramName.Trim()).GetValue(src, null));

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify.
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Create, storage))
            using (StreamWriter writer = new StreamWriter(stream))
            {
                writer.Write((new JavaScriptSerializer()).Serialize(items));
            }

        }
        catch (Exception) { }   // If fails - just don't use preferences
    }

    internal static void Load(object tar, string fileName)
    {
        Dictionary<string, object> items = new Dictionary<string, object>();
        Type type = tar.GetType();

        try
        {
            // GetUserStoreForApplication doesn't work - can't identify
            // application unless published by ClickOnce or Silverlight
            IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForAssembly();
            using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(fileName, FileMode.Open, storage))
            using (StreamReader reader = new StreamReader(stream))
            {
                items = (new JavaScriptSerializer()).Deserialize<Dictionary<string, object>>(reader.ReadToEnd());
            }
        }
        catch (Exception) { return; }   // If fails - just don't use preferences.

        foreach (KeyValuePair<string, object> obj in items)
        {
            try
            {
                tar.GetType().GetProperty(obj.Key).SetValue(tar, obj.Value, null);
            }
            catch (Exception) { }
        }
    }
}

评论

1赞 Boczek 11/25/2011
或者更好;使用 DataContractJsonSerializer
3赞 user3130351 12/24/2013 #8

有时,您希望删除传统 web.config 或 app.config 文件中保留的那些设置。您希望对设置条目和分离数据设计的部署进行更精细的控制。或者要求是在运行时添加新条目。

我可以想象两个不错的选择:

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

强类型版本的优点是强类型设置名称和值。不存在混用名称或数据类型的风险。缺点是必须对更多设置进行编码,无法在运行时添加。

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

您可以在此处找到两个功能齐全的实现的代码。

6赞 kite 9/19/2014 #9

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

  • 如果您使用 .NET 4.0 dynamic,则此库非常易于使用 (序列化、反序列化、嵌套对象支持和排序输出 随心所欲 + 将多个设置合并为一个) JsonConfig(用法等同于 ApplicationSettingsBase)
  • 对于 .NET YAML 配置库...我还没有找到一个像 易于用作 JsonConfig

您可以将设置文件存储在多个特殊文件夹(适用于所有用户和每个用户)中,如下所示:Environment.SpecialFolder 枚举和多个文件(默认只读、每个角色、每个用户等)

如果选择使用多个设置,则可以合并这些设置:例如,合并 default + BasicUser + AdminUser 的设置。您可以使用自己的规则:最后一个规则覆盖值,依此类推。

18赞 Dieter Meemken 11/25/2015 #10

一个简单的方法是使用配置数据对象,将其保存为本地文件夹中带有应用程序名称的 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();
        }
    }
}

现在,您可以创建一个实例,并在表单的 load 和 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>

评论

1赞 Philip Stratford 3/2/2017
我在开发中效果很好,但是当我部署应用程序时,普通用户无权访问该文件夹,因此保存设置会引发错误。我正在考虑将 xml 文件保存在 AppData 中,但我只是想知道是否有明显的方法可以解决这个问题,因为这种方法似乎对您有用。c:\program files\my application
0赞 Dieter Meemken 3/6/2017
@PhilipStratford 由于它只是一个普通文件,因此您可以将其保存在任何地方。只需找到一个具有写入权限的地方即可。
0赞 Dieter Meemken 3/6/2017
@PhilipStratford AppData 文件夹可能是一个选项,请参阅 C# 获取 %AppData% 的路径,如 kite 所述。
0赞 Philip Stratford 3/8/2017
谢谢,我已经实现了这个,将xml文件保存在AppDate文件夹中。我只是想知道是否有一种简单的方法可以按照您的示例将其保存在应用程序的文件夹中,因为我认为您已经使它正常工作。不用担心,无论如何,AppData 文件夹可能是一个更好的位置!
20赞 anakic 6/8/2016 #11

我想分享我为此构建的库。这是一个很小的库,但对 .settings 文件有很大的改进(恕我直言)。

该库称为 Jot (GitHub)。这是我写的一篇关于代码项目的旧文章

以下是如何使用它来跟踪窗口的大小和位置:

public MainWindow()
{
    InitializeComponent();

    _stateTracker.Configure(this)
        .IdentifyAs("MyMainWindow")
        .AddProperties(nameof(Height), nameof(Width), nameof(Left), nameof(Top), nameof(WindowState))
        .RegisterPersistTrigger(nameof(Closed))
        .Apply();
}

与 .settings 文件相比的优势:代码要少得多,而且出错的可能性也小得多,因为您只需要提及每个属性一次

使用设置文件时,需要提及每个属性五次:一次是在显式创建属性时,另外四次在来回复制值的代码中。

存储、序列化等是完全可配置的。当目标对象由 IoC 容器创建时,您可以 [挂钩][],以便它自动将跟踪应用于它解析的所有对象,这样,要使属性持久化,您需要做的就是在其上打一个 [Trackable] 属性。

它是高度可配置的,您可以配置: - 当数据被全局保存和应用时,或针对每个被跟踪对象 - 如何序列化 - 存储位置(例如文件、数据库、联机、独立存储、注册表) - 可以取消为属性应用/保留数据的规则

相信我,图书馆是一流的!

2赞 Paul - Soura Tech LLC 7/28/2016 #12
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();
    }
}

评论

0赞 Moiyd 6/25/2021
你能澄清一下设置文件在哪里吗?或者它看起来像什么?
9赞 Turker Tunali 12/15/2017 #13

“这是否意味着我应该使用自定义 XML 文件来保存配置设置?”不,不一定。我们使用 SharpConfig 进行此类操作。

例如,如果配置文件是这样的

[General]
# a comment
SomeString = Hello World!
SomeInteger = 10 # an inline comment

我们可以检索这样的值

var config = Configuration.LoadFromFile("sample.cfg");
var section = config["General"];

string someString = section["SomeString"].StringValue;
int someInteger = section["SomeInteger"].IntValue;

它与 .NET 2.0 及更高版本兼容。我们可以即时创建配置文件,以后可以保存。

资料来源:http://sharpconfig.net/
GitHub:https://github.com/cemdervis/SharpConfig

评论

0赞 Moiyd 6/25/2021
非常好的答案,挽救了我的一天。谢谢!假设我需要添加更多参数,如何使用代码修改该文件?再次感谢。
1赞 Turker Tunali 6/26/2021
请参阅 github.com/cemdervis/SharpConfig 中的“在内存中创建配置”和“保存配置”。
18赞 Matt 1/23/2020 #14

是的,可以保存配置 - 但这在很大程度上取决于您选择的方式。让我描述一下技术差异,以便您了解您拥有的选项:

首先,您需要区分是否要在(也称为 Visual Studio)文件中使用 applicationSettingsAppSettings - 存在根本差异,此处将对此进行描述*.exe.configApp.config

两者都提供了保存更改的不同方法:

  • AppSettings 允许您通过 直接读取和写入配置文件,其中 config 定义为:config.Save(ConfigurationSaveMode.Modified);
    config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
  • applicationSettings 允许读取,但如果您写入更改(通过 ),它将基于每个用户写入,存储在特殊位置(例如 )。正如 Hans Passant 在他的回答中提到的,这是因为用户通常对 Program Files 具有受限权限,并且如果不调用 UAC 提示符就无法写入它。缺点是,如果将来要添加配置键,则需要将它们与每个用户配置文件同步。Properties.Settings.Default.Save();C:\Documents and Settings\USERID\Local Settings\Application Data\FIRMNAME\WindowsFormsTestApplicati_Url_tdq2oylz33rzq00sxhvxucu5edw2oghw\1.0.0.0

但还有其他几个替代选项:

  • 从 .NET Core(以及 .NET 5 和 6)开始,第三个选项是使用 Microsoft 配置抽象的文件(以及存储在用户配置文件中而不是程序集目录中的文件)。但通常WinForms不使用它,所以我提到它只是为了完整。但是,这里有一些关于如何读取写入值的参考。或者,您可以使用 Newtonsoft JSON 来读取和写入文件,但不限于此:您还可以使用该方法创建自己的 JSON 文件。appsettings.jsonsecrets.jsonappsettings.json

  • 如问题中所述,还有第 4 个选项:如果将配置文件视为 XML 文档,则可以使用 System.Xml.Linq.XDocument 类加载、修改和保存它。不需要使用自定义XML文件,可以读取已有的配置文件;对于查询元素,您甚至可以使用 Linq 查询。我在这里给出了一个示例,请查看答案中的函数 GetApplicationSetting

  • 第 5 个选项是将设置存储在注册表中。这里描述了如何做到这一点。

  • 最后,还有第六个选项:您可以将值存储在环境(系统环境或帐户环境)中。在 Windows 设置(Windows 菜单中的齿轮)中,在搜索栏中输入“环境”并在那里添加或编辑它们。要阅读它们,请使用

    请注意,通常需要重新启动应用程序才能获取更新的环境设置。
    var myValue = Environment.GetEnvironmentVariable("MyVariable");

如果您需要加密来保护您的值,请查看答案。它介绍如何使用 Microsoft 的 DPAPI 来存储加密的值。

如果要支持自己的文件,无论是 XML 还是 JSON,了解正在运行的程序集的目录可能很有用:

var assemblyDLL = System.Reflection.Assembly.GetExecutingAssembly();
var assemblyDirectory = System.IO.Path.GetDirectoryName(assemblyDLL.Location);

您可以用作存储文件的基本目录。assemblyDirectory