如何在.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个回答

18
我已经使用过这段代码并得到了解决方案。
AppDomain.CurrentDomain.BaseDirectory

15

以下代码将会给你应用程序的路径:

var applicationPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)

上述方案在以下情况下可以正常工作:

  • 简单应用程序
  • 在另一个域中,其中Assembly.GetEntryAssembly()将返回null
  • 已将DLL作为字节数组从嵌入的资源加载并作为Assembly.Load(byteArrayOfEmbeddedDll)加载到AppDomain中
  • 使用Mono的绑定(其他方法无效)

2
在 Linux 上调试器下,这将返回:/usr/share/dotnet。 - Vladimir

9
您可以简单地添加到您的项目引用System.Windows.Forms,然后像往常一样使用System.Windows.Forms.Application.StartupPath。所以,不需要更复杂的方法或使用反射。

我使用了那个方法,它运行良好。但有一次我在我的单元测试项目中使用了该方法。当然,它失败了,因为它在 C:\PROGRAM FILES (X86)\MICROSOFT VISUAL STUDIO 14.0\COMMON7\IDE\COMMONEXTENSIONS\MICROSOFT\TESTWINDOW 中寻找我的文件。 - ainasiart
@ainasiart 那么我该如何在单元测试中让它正常工作呢? - Nicholas Siegmundt

8
我已经使用过。
System.AppDomain.CurrentDomain.BaseDirectory

当我想要查找相对于应用程序文件夹的路径时。这适用于ASP.Net和winform应用程序。它也不需要引用System.Web程序集。


7

我没有看到有人将 .Net Core 反射提供的 LocalPath 转换为可用的 System.IO 路径,因此这是我的版本。

public static string GetApplicationRoot()
{
   var exePath = new Uri(System.Reflection.
   Assembly.GetExecutingAssembly().CodeBase).LocalPath;

   return new FileInfo(exePath).DirectoryName;
       
}

这将返回格式化后的完整路径 C:\\xxx\\xxx,指向你的代码所在的位置。

我不明白 Uri(System.Reflection.Assembly.GetExecutingAssembly().CodeBase).LocalPathSystem.Reflection.Assembly.GetExecutingAssembly().CodeBase 有什么区别,您能详细说明一下吗? - RonC

7
我的意思是,为什么不使用p/invoke方法呢?
    using System;
    using System.IO;
    using System.Runtime.InteropServices;
    using System.Text;
    public class AppInfo
    {
            [DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = false)]
            private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
            private static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
            public static string StartupPath
            {
                get
                {
                    StringBuilder stringBuilder = new StringBuilder(260);
                    GetModuleFileName(NullHandleRef, stringBuilder, stringBuilder.Capacity);
                    return Path.GetDirectoryName(stringBuilder.ToString());
                }
            }
    }

您可以像使用 Application.StartupPath 一样使用它:

    Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");

2
为什么要使用p/invoke,既然有这么多.NET可以做到这一点? - ProfK
7
因为它需要与Windows进行强依赖,并且与DNX或Mono不兼容。也许在未来的Windows版本中有重大变化。所以再次问:为什么我们应该在这里使用P/Invoke? - Benjamin Abt

6

在VB.net中

My.Application.Info.DirectoryPath

对我来说可行(应用程序类型:类库)。不确定C#是否适用... 返回不带文件名的路径作为字符串


6

如果exe文件是通过双击来调用的,我会使用这个方法

var thisPath = System.IO.Directory.GetCurrentDirectory();

5
这不正确,因为结果中可能会出现随机目录。 - amuliar
此命令返回 Environment.CurrentDirectory,但该路径在运行时可能会更改为任何路径,因此不是一个可靠的解决方案。 - Yury Kozlov

6

虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会失效。-【来自审查】 - Erik McKelvey
2
@ErikMcKelvey 他们提供了一个解决方案和一份文档的参考,表明这确实是一个解决方案。如果不使用链接,你会如何引用一个解决方案? - Scratte
@Scratte他的意思不是说应该放弃链接;相反,他说*...并提供参考链接。*在SO上,常识是仅有链接的答案可能会很快变得无用,因为链接目标往往很快消失。因此,最好发布链接,但另外尝试至少将链接所指向页面的最基本信息纳入其中。 - Binarus
1
@Binarus 他们说了。他们说“.NET 6有Environment.ProcessPath”,这是“必要的部分”。这就是所有人需要知道的,以便继续解决方案。链接只是对“Environment.ProcessPath”的参考。它是额外的,所以不需要谷歌“Environment.ProcessPath”的人可以忽略它。你点击了链接吗?你认为应该从中复制粘贴什么? - Scratte
嗯,在这种情况下你可能是对的。我只是试图解释一下埃里克·麦凯尔维(Erik McKelvey)在回复你的第一个评论时的意思。 - Binarus

6

Assembly.GetEntryAssembly().LocationAssembly.GetExecutingAssembly().Location

System.IO.Path.GetDirectoryName()结合使用,仅获取目录。

GetEntryAssembly()GetExecutingAssembly()中的路径可能不同,即使大多数情况下目录相同。

使用GetEntryAssembly()时必须注意,如果入口模块未经管理(例如C++或VB6可执行文件),则此函数可能返回null。在这些情况下,可以从Win32 API中使用GetModuleFileName

[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);

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