如何在.NET控制台应用程序中获取应用程序路径?

1130

如何在控制台应用程序中找到应用程序的路径?

Windows Forms 中,我可以使用 Application.StartupPath 找到当前路径,但在控制台应用程序中似乎不可用。


7
您是否在目标(客户端、开发)机器上安装了.NET Framework?如果是,您可以添加对System.Windows.Forms.dll的引用,并使用Application.StartupPath!这是最好的方法,如果您想消除更多未来的异常情况! - Ehsan Mohammadi
AppDomain.BaseDirectory是应用程序目录。请注意,在VS环境和Win环境下,应用程序可能会表现不同。但是AppDomain应该是相同的,不是作为application.path,但我希望这不仅适用于IIS。 - Mertuarez
30个回答

1348

System.Reflection.Assembly.GetExecutingAssembly().Location1

如果您只需要目录,请与System.IO.Path.GetDirectoryName结合使用。

1根据Mindor先生的评论:
System.Reflection.Assembly.GetExecutingAssembly().Location 返回当前执行程序集所在的位置,这可能与未执行时程序集所在的位置相同也可能不同。在进行阴影复制程序集的情况下,您将获得临时目录中的路径。System.Reflection.Assembly.GetExecutingAssembly().CodeBase 将返回程序集的“永久”路径。


264
System.Reflection.Assembly.GetExecutingAssembly().Location会返回当前执行的程序集所在的位置,这个位置可能和程序集非执行时所在的位置不同。如果是影子复制的程序集,则会得到一个临时目录的路径。System.Reflection.Assembly.GetExecutingAssembly().CodeBase会返回程序集的“永久”路径。 - Mr.Mindor
17
这取决于它的使用方式:https://dev59.com/LUjSa4cB1Zd3GeqPDj2s。或者您可以使用以下代码: new Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPath - Mr.Mindor
47
GetExecutingAssembly返回包含当前正在执行的代码的程序集。这可能不一定是控制台.exe程序集,它可能是从完全不同的位置加载的程序集。你需要使用GetEntryAssembly!此外请注意,在程序集位于GAC中时,可能未设置CodeBase。更好的选择是AppDomain.CurrentDomain.BaseDirectory - bitbonk
4
如果你调用DLL,System.Reflection.Assembly.GetExecutingAssembly().CodeBase会得到"file:///C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"。 - raidsan
5
对于控制台应用程序,不存在“应用程序(Application)”一词。 - Sam Axe
显示剩余14条评论

478
您可以使用以下代码获取当前应用程序目录。
AppDomain.CurrentDomain.BaseDirectory

57
不要使用这个。BaseDirectory可以在运行时设置。它不能保证是正确的(就像被接受的回答那样)。 - usr
4
这很可能是你想要的答案,因为它可以补偿影子复制。 - George Mauer
4
您为什么认为BaseDirectory可以在运行时设置?它只有一个getter(获取器)。 - bitbonk
3
@bitbonk 可以在应用程序域创建时设置。 - usr
3
"在*.lnk文件中,“起始位置:”字段不是可以更改BaseDirectory吗?" - Alexander
显示剩余4条评论

212
你有两个选项来找到应用程序的目录,你的选择将取决于你的目的。
// To get the location the assembly is executing from
// (not necessarily where it normally resides on disk).
// In the case of using shadow copies, for instance in NUnit tests, 
// this will be in a temp directory.
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;

// To get the location the assembly normally resides on disk or the install directory
string path = System.Reflection.Assembly.GetExecutingAssembly().CodeBase;

// Once you have the path you get the directory with:
var directory = System.IO.Path.GetDirectoryName(path);

3
只是想说,显然有很多超过2个选项,因为已经发布了许多其他选择... - vapcguy
21
如果你尝试的操作不支持URI格式,可以使用var localDirectory = new Uri(directory).LocalPath;。该语句将目录路径转换为本地文件系统路径,以便在不支持URI格式的情况下执行操作。请注意,该语句不会改变原始意思。 - Scott Solmer
这完全是错的。如果可执行文件根本不是.NET程序集,那该怎么办?正确的答案是检查环境并检查命令行。 - mark
2
@Ukuma.Scott 如果路径包含 & 或 #,则此方法无法正常工作。 - MatsW
@mark 请问您能告诉我实际的代码是什么吗? - Grace
@Grace - 这段话太长了。如果你的exe只是一个.NET应用程序,那么建议的方法应该已经足够好了。 - mark

99

可能有点晚,但值得一提:

Environment.GetCommandLineArgs()[0];

更准确地说,要获取只有目录路径:

System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);

编辑:

许多人指出,GetCommandLineArgs不能保证返回程序名称。请参见命令行上的第一个单词只是传统意义上的程序名称。该文章确实指出:“虽然极少数的Windows程序使用这种怪癖(我自己不知道有哪些)”。因此,“假冒”GetCommandLineArgs是可能的,但我们正在谈论控制台应用程序。控制台应用程序通常是快速且粗略的。所以这符合我的KISS理念。

编辑: 从反馈中看,大多数其他解决方案在使用单元测试系统时无法正常工作。这也是有道理的,因为可执行项不是您的应用程序,而是测试系统。我没有验证过这一点 - 所以我可能完全错了。如果是这样,我会删除这个编辑。


1
@usr,你所提到的情况高度理论化。在控制台应用程序的上下文中,使用其他方法并没有什么意义。保持简单! - Steve Mc
1
@usr mmm - 看一下任务管理器的命令行列,可以证实我的说法。有几个只有exe名称的系统服务。不要紧。我想说的是,在开发控制台应用程序时,没有必要把事情搞得比必要的更复杂。特别是当我们已经有可用的信息时。现在,如果您以某种方式运行控制台应用程序以欺骗GetCommandLineArgs,那么您已经在跳过障碍了,您可能需要问自己是否控制台应用程序是正确的选择。 - Steve Mc
6
你的“简单”解决方案需要调用两个方法。而“复杂”的解决方案也需要调用两个方法。实际上没有什么区别,除非在编写程序时无法控制某些情况下,“简单”解决方案可能会给出错误的答案。为什么要冒险呢?使用另外两个方法调用,你的程序将不会更加复杂,而且更可靠。 - Chris
3
这个方案适用于我的情况,其他解决方案不行,所以感谢提供另一种选择 :-) 我使用ReSharper测试运行器来运行MS单元测试,我正在测试的代码需要一个特定的.dll文件在执行目录中...但是Assembly.GetExecutingDirectory()返回了一个奇怪的结果。 - wallismark
1
@Chris - 为了支持这个答案辩护。它适用于单元测试,而GetEntryAssembly解决方案不行,因为GetEntryAssembly返回null。那些提出GetExecutingAssembly的答案是虚假的,因为它们只在执行程序集是可执行文件时才返回可执行文件。这不是简单,但是正确的解决方案。 - mark
显示剩余5条评论

51

对于任何对asp.net web应用程序感兴趣的人,这里是我对3种不同方法的结果。

protected void Application_Start(object sender, EventArgs e)
{
  string p1 = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
  string p2 = System.Web.Hosting.HostingEnvironment.ApplicationPhysicalPath;
  string p3 = this.Server.MapPath("");
  Console.WriteLine("p1 = " + p1);
  Console.WriteLine("p2 = " + p2);
  Console.WriteLine("p3 = " + p3);
}

结果

p1 = C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\a897dd66\ec73ff95\assembly\dl3\ff65202d\29daade3_5e84cc01
p2 = C:\inetpub\SBSPortal_staging\
p3 = C:\inetpub\SBSPortal_staging

该应用程序实际上正在从"C:\inetpub\SBSPortal_staging"运行,因此第一种解决方案绝对不适用于Web应用程序。


47
上面的答案对我来说已经解决了90%的问题,但是它返回的是Uri而不是普通路径。
如 MSDN 论坛帖子中所解释的,我使用了以下代码:如何将 URI 路径转换为普通文件路径?
// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;

1
如果所讨论的exe是Windows服务,而当前目录返回C:\ Windows \ system32,则此方法也可以正常工作。上述代码返回exe的实际位置。 - Linda Lawton - DaImTo
除非你尝试执行类似于File.CreateDirectory(path)的操作,否则它会抛出异常,因为它不允许URI路径... - vapcguy
2
不幸的是,这对包含片段标识符(#字符)的路径无效。标识符及其后面的所有内容都将从结果路径中截断。 - bgfvdu3w
为什么不交换 new UriSystem.IO.Path.GetDirectoryName?这样可以得到一个普通的路径字符串,而不是一个 Uri - Timo
我认为这是最好的方法。在任何环境下,这种方法都能可靠地工作。在生产中、本地调试、单元测试中都是如此...想要打开一个在单元测试中包含的内容文件(“复制最新内容”)吗?它就在那里。 - Timo

42

如果你正在寻找一个与 .NET Core 兼容的方式,请使用

System.AppContext.BaseDirectory

这是在.NET Framework 4.6和.NET Core 1.0(以及.NET Standard 1.3)中引入的。请参见:AppContext.BaseDirectory Property

根据此页面

这是.NET Core中AppDomain.CurrentDomain.BaseDirectory的首选替代方法。


4
请参考 https://github.com/dotnet/runtime/issues/13051 获取自包含的 dotnet 控制台应用程序。建议使用 Process.GetCurrentProcess().MainModule.FileName - Gavin
@Gavin 这在 .NET 5 之前是正确的。使用 .NET 5 或更高版本,请使用 AppContext.BaseDirectory。请参阅 https://www.hanselman.com/blog/how-do-i-find-which-directory-my-net-core-console-application-was-started-in-or-is-running-from。 - TiltonJH

32

您可能正在寻找以下内容:

System.IO.Path.GetDirectoryName(
    System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)

1
请注意,这会返回一个URI,但并非所有情况都支持。 - Denise Skidmore

29

你可以使用这一个代替。

System.Environment.CurrentDirectory

这将获取可执行文件的文件夹。 - Iain
1
这可以通过多种方式进行更改(例如快捷设置等)...最好不要使用它。 - Yousha Aleayoub

22

对于控制台应用程序,您可以尝试以下方法:

System.IO.Directory.GetCurrentDirectory();

输出结果(在我的本地电脑上):

c:\users\xxxxxxx\documents\visual studio 2012\Projects\ImageHandler\GetDir\bin\Debug

或者您可以尝试(末尾有一个额外的反斜杠):

AppDomain.CurrentDomain.BaseDirectory

输出:

c:\users\xxxxxxx\documents\visual studio 2012\Projects\ImageHandler\GetDir\bin\Debug\


1
BaseDirectory 可以在运行时设置。但不能保证其正确性。 - Yousha Aleayoub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接