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


951

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

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


5
是否在目标(客户端,开发)计算机上安装.NET Framework?如果您的回答是正确的;因此,您可以添加对System.Windows.Forms.dll的引用并使用Application.StartupPath!如果您想放弃以后的例外,这是最好的方法!
Ehsan Mohammadi

AppDomain.BaseDirectory是应用程序目录。请注意,在VS env和Win env中,应用程序的行为可能有所不同。但是AppDomain不应与application.path相同,但我希望这不仅适用于IIS。
Mertuarez '16

Answers:


1178

System.Reflection.Assembly.GetExecutingAssembly()1个Location

System.IO.Path.GetDirectoryName如果只需要目录,则将其与。

1 根据Mindor先生的评论:
System.Reflection.Assembly.GetExecutingAssembly().Location返回正在执行的程序集的当前位置,不执行时可能会或可能不在该程序集的位置。对于卷影复制程序集,您将在temp目录中获得一个路径。System.Reflection.Assembly.GetExecutingAssembly().CodeBase将返回程序集的“永久”路径。


243
System.Reflection.Assembly.GetExecutingAssembly()。Location返回正在执行的程序集的当前位置,该位置可能不执行时即为程序集的位置。对于卷影复制程序集,您将在temp目录中获得一个路径。System.Reflection.Assembly.GetExecutingAssembly()。CodeBase将返回程序集的“ 永久 ”路径。
2011年

13
@SamGoldberg:取决于使用方式:stackoverflow.com/q/1068420/391656。或者,您可以... new Uri(System.Reflection.Assembly.GetExecutingAssembly()。CodeBase).LocalPath
Mr.Mindor 2012年

28
GetExecutingAssembly返回包含当前正在执行的代码的程序集。不一定是控制台.exe程序集。它可能是从完全不同的位置加载的装配体。您将不得不使用GetEntryAssembly!另请注意,CodeBase当程序集位于GAC中时,可能未设置。更好的选择是AppDomain.CurrentDomain.BaseDirectory
bitbonk 2015年

3
请在4个空格中编写代码,以便于复制
fnc12

3
如果您调用dll,System.Reflection.Assembly.GetExecutingAssembly()。CodeBase将获得“ file:/// C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll”
raidsan

407

您可以使用以下代码来获取当前应用程序目录。

AppDomain.CurrentDomain.BaseDirectory

42
不要使用这个。可以在运行时设置BaseDirectory。不保证它是正确的(就像接受的答案一样)。
usr 2012年

3
+1这可能是您想要的答案,因为它可以补偿卷影复制。
乔治·莫尔

4
@usr是什么让您认为BaseDirectory可以在运行时设置?它只有一个吸气剂。
bitbonk 2015年

3
@bitbonk可以在创建应用程序域时设置。
usr

3
是不是可以在* .lnk文件的“开始于:”字段中更改BaseDirectory?
亚历山大

170

您可以通过两个选项来查找应用程序的目录,具体取决于您的用途。

// to get the location the assembly is executing from
//(not necessarily where the it normally resides on disk)
// in the case of the 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 2016年

17
如果您尝试使用上述路径进行的操作都不支持URI格式,请使用var localDirectory = new Uri(directory).LocalPath;
Scott Solmer

这是错误的。根本不是.NET程序集的可执行文件是什么?正确的答案是检查环境并检查命令行。
标记

@ Ukuma.Scott如果路径包含&或#,则此方法不起作用
MatsW

82

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

Environment.GetCommandLineArgs()[0];

或者更正确地获取目录路径:

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

编辑:

不少人指出,GetCommandLineArgs不能保证返回程序名称。请参阅命令行上的第一个单词仅是约定的程序名称。这篇文章确实指出“尽管很少有Windows程序使用此怪癖(我自己都不知道)”。因此可以“欺骗” GetCommandLineArgs,但我们正在谈论控制台应用程序。控制台应用程序通常又快又脏。因此,这符合我的KISS哲学。


1
@usr您提到的情况是高度理论性的。在控制台应用程序的上下文中,使用任何其他方法实际上没有任何意义。把事情简单化!
史蒂夫·麦克

1
@usr mmm-查看taskmgr cmdline列来备份我的意思。仅有exe名称的一些系统服务。没关系。我要说的是,在开发控制台应用程序时,无需使事情变得比需要的复杂。特别是当我们已经有可用信息时。现在,如果您以欺骗GetCommandLineArgs的方式运行控制台应用程序,那么您已经跳了圈,您可能需要问问自己,控制台应用程序是否是正确的选择。
史蒂夫·麦克

5
您的“简单”解决方案涉及两个方法调用。“复杂”的解决方案涉及两个方法调用。没有实际的区别-除了“简单”的解决方案在编写程序时不受您控制的某些情况下可以为您提供错误的答案。为什么要冒险?使用其他两个方法调用,您的程序将不再复杂,但将更加可靠。
克里斯,

3
在我的情况下可以使用,其他解决方案则没有,因此感谢您提供另一种选择:-)我正在使用ReSharper测试运行程序来运行MS单元测试,并且正在测试的代码需要在执行目录中包含特定的.dll。 ..and Assembly.GetExecutingDirectory()奇怪地返回了不同的结果。
wallismark 2015年

1
@克里斯-为这个答案辩护。它适用于单元测试,但GetEntryAssembly解决方案无效,因为GetEntryAssembly返回null。提出GetExecutingAssembly的答案是虚假的,因为它们仅在执行程序集是可执行文件时才返回可执行文件。这不是简单的,而是正确的解决方案。
标记

44

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

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应用程序。


42

上面的答案是我需要的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的实际位置
DaImTo 2015年

除非您随后尝试执行类似的操作File.CreateDirectory(path),否则它将为您提供一个例外,即它不允许URI路径...
vapcguy

1
不幸的是,这对于包含片段标识符(#字符)的路径不起作用。标识符及其后的所有内容将从结果路径中截断。
bgfvdu3w

你为什么不换new UriSystem.IO.Path.GetDirectoryName?这将为您提供一个普通的路径字符串,而不是一个Uri
Timo '18

我觉得这是最好的。在任何环境下,这种方法对我来说都是可靠的。在生产中,本地调试,单元测试...是否要打开单元测试中包含的内容文件(“内容-如果较新,请复制”)?在那里。
Timo

29

您可能正在寻找这样做:

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

23

您可以改用这个。

System.Environment.CurrentDirectory

不过,这将获取可执行文件的文件夹
Iain 2012年

可以通过多种方式(快捷方式设置等)进行更改...最好不要使用它。
Yousha Aleayoub

23

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

System.AppContext.BaseDirectory

.NET Framework 4.6和.NET Core 1.0(和.NET Standard 1.3)中对此进行了介绍。请参阅:AppContext.BaseDirectory属性

根据此页面

这是.NET Core中AppDomain.CurrentDomain.BaseDirectory的首选替代品


有关自包含的dotnet控制台应用程序,另请参见github.com/dotnet/runtime/issues/13051。建议使用Process.GetCurrentProcess().MainModule.FileName
Gavin

19

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

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 \


BaseDirectory可以在运行时设置。不保证是正确的”
Yousha Aleayoub


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

7

如果应该通过双击来调用该exe文件,则可以使用它

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

5
这是不正确的,因为您可以得到随机目录。
2013年

该命令返回Environment.CurrentDirectory,可以在运行时将其更改为任何路径,因此它不是可靠的解决方案。
尤里·科兹洛夫

7

我用过了

System.AppDomain.CurrentDomain.BaseDirectory

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


7

下一行将为您提供一个应用程序路径:

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

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

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

在Linux上的调试器下,此命令返回:/ usr / share / dotnet
Vladimir

6

我的意思是,为什么不使用ap / 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
.NET太多时,为什么要p / invoke?
ProfK

7
@ user3596865,因为它需要对Windows的严格依赖,并且与DNX或Mono不兼容。也许将来的Windows版本会有重大变化。再说一遍:为什么我们应该在这里使用pinvoke?

5

Assembly.GetEntryAssembly().Location 要么 Assembly.GetExecutingAssembly().Location

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

尽管大多数情况下目录是相同的,但来自GetEntryAssembly()和的路径GetExecutingAssembly()可以不同。

随着GetEntryAssembly()你要知道,这可以返回null,如果输入模块未被管理(即C ++或VB6可执行文件)。在这种情况下,可以使用GetModuleFileNameWin32 API:

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

5

在VB.net

My.Application.Info.DirectoryPath

为我工作(应用程序类型:类库)。不确定C#...将不带文件名的路径作为字符串返回


4
AppDomain.CurrentDomain.BaseDirectory

将解决此问题,以使用安装程序包引用第三方参考文件。


11
这个答案已经在5年前提出过,甚至不止一次。
2014年

2

这些方法在特殊情况下均无法使用,例如使用指向exe的符号链接,它们将返回链接的位置而不是实际exe。

因此可以使用QueryFullProcessImageName来解决此问题:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Diagnostics;

internal static class NativeMethods
{
    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern bool QueryFullProcessImageName([In]IntPtr hProcess, [In]int dwFlags, [Out]StringBuilder lpExeName, ref int lpdwSize);

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr OpenProcess(
        UInt32 dwDesiredAccess,
        [MarshalAs(UnmanagedType.Bool)]
        Boolean bInheritHandle,
        Int32 dwProcessId
    );
}

public static class utils
{

    private const UInt32 PROCESS_QUERY_INFORMATION = 0x400;
    private const UInt32 PROCESS_VM_READ = 0x010;

    public static string getfolder()
    {
        Int32 pid = Process.GetCurrentProcess().Id;
        int capacity = 2000;
        StringBuilder sb = new StringBuilder(capacity);
        IntPtr proc;

        if ((proc = NativeMethods.OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid)) == IntPtr.Zero)
            return "";

        NativeMethods.QueryFullProcessImageName(proc, 0, sb, ref capacity);

        string fullPath = sb.ToString(0, capacity);

        return Path.GetDirectoryName(fullPath) + @"\";
    }
}

2

尝试以下简单的代码行:

 string exePath = Path.GetDirectoryName( Application.ExecutablePath);

1

另一种解决方案是使用指向当前路径的相对路径:

Path.GetFullPath(".")

这将获取当前目录,而不是启动EXE的位置。
四时

0

我没有看到任何人将.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”格式的路径返回到您的代码所在的位置。



-1

这是可与32位64位应用程序一起使用的可靠解决方案。

添加以下参考:

使用System.Diagnostics;

使用System.Management;

将此方法添加到您的项目中:

public static string GetProcessPath(int processId)
{
    string MethodResult = "";
    try
    {
        string Query = "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId;

        using (ManagementObjectSearcher mos = new ManagementObjectSearcher(Query))
        {
            using (ManagementObjectCollection moc = mos.Get())
            {
                string ExecutablePath = (from mo in moc.Cast<ManagementObject>() select mo["ExecutablePath"]).First().ToString();

                MethodResult = ExecutablePath;

            }

        }

    }
    catch //(Exception ex)
    {
        //ex.HandleException();
    }
    return MethodResult;
}

现在像这样使用它:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

请注意,如果您知道进程的ID,则此方法将返回相应的ExecutePath。

另外,对于那些感兴趣的人:

Process.GetProcesses() 

...将为您提供所有当前正在运行的进程的数组,并且...

Process.GetCurrentProcess()

...将为您提供当前的流程,以及其信息(例如ID等)以及有限的控制权(例如Kill等)*


-5

您可以使用解决方案资源管理器在项目中将文件夹名称创建为资源,然后将文件粘贴到资源中。

private void Form1_Load(object sender, EventArgs e) {
    string appName = Environment.CurrentDirectory;
    int l = appName.Length;
    int h = appName.LastIndexOf("bin");
    string ll = appName.Remove(h);                
    string g = ll + "Resources\\sample.txt";
    System.Diagnostics.Process.Start(g);
}

6
使用Environment.CurrentDirectory是非常错误的,请不要使用它!该路径可以在运行时更改。即使在启动时,它也是不确定的。
usr
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.