关于C#:如何在.NET控制台应用程序中获取应用程序的路径?

How can I get the application's path in a .NET console application?

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

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


System.Reflection.Assembly.GetExecutingAssembly().Location1

如果您只需要目录,那么可以将它与System.IO.Path.GetDirectoryName结合起来。

1As per Mr.Mindor's comment:
System.Reflection.Assembly.GetExecutingAssembly().Location returns where the executing assembly is currently located, which may or may not be where the assembly is located when not executing. In the case of shadow copying assemblies, you will get a path in a temp directory. System.Reflection.Assembly.GetExecutingAssembly().CodeBase will return the 'permanent' path of the assembly.


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

1
AppDomain.CurrentDomain.BaseDirectory


您有两个选择来查找应用程序的目录,您选择的目录将取决于您的目的。

1
2
3
4
5
6
7
8
9
10
11
// 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);


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

1
Environment.GetCommandLineArgs()[0];

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

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

编辑:

相当多的人指出,GetCommandLineArgs不能保证返回程序名。请参见命令行上的第一个词,它是仅按约定的程序名。这篇文章确实指出,"尽管很少有Windows程序使用这种怪癖(我自己也不知道)"。所以"欺骗"GetCommandLineArgs是可能的,但我们讨论的是控制台应用程序。控制台应用程序通常是快速和肮脏的。所以这符合我的亲吻理念。


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

1
2
3
4
5
6
7
8
9
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);
}

结果

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

该应用程序实际上是从"c:inetpubsbsportal_staging"运行的,因此第一个解决方案绝对不适合Web应用程序。


上面的答案是我需要的90%,但返回的是一个URI而不是常规路径。

如msdn论坛帖子中所述,如何将uri路径转换为普通文件路径?,我使用了以下内容:

1
2
3
4
5
// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;


您可能希望这样做:

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

你可以用这个代替。

1
System.Environment.CurrentDirectory


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

1
System.IO.Directory.GetCurrentDirectory();

输出(在本地计算机上):

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

或者你可以尝试(结尾还有一个反斜杠):

1
AppDomain.CurrentDomain.BaseDirectory

输出:

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


我已经使用了这个代码并得到了解决方案。

1
AppDomain.CurrentDomain.BaseDirectory

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

1
System.AppContext.BaseDirectory

这是在.NET框架4.6和.NET核心1.0(和.NET标准1.3)中引入的。请参见:AppContext.BaseDirectory属性。

根据这一页,

This is the prefered replacement for AppDomain.CurrentDomain.BaseDirectory in .NET Core


如果要通过双击来调用exe,则使用此选项

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


我已经用过

1
System.AppDomain.CurrentDomain.BaseDirectory

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


您可以简单地将System.Windows.Forms添加到项目引用中,然后像往常一样使用System.Windows.Forms.Application.StartupPath

所以,不需要更复杂的方法或使用反射。


我的意思是,为什么不使用p/invoke方法?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    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那样使用它:

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


在VB.net

1
My.Application.Info.DirectoryPath

适用于我(应用程序类型:类库)。不确定C……以字符串形式返回路径w/o文件名


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

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

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

如果使用EDOCX1,8,您必须知道,如果输入模块是非托管的(即C++或VB6可执行文件),那么它可以返回EDCOX1×11。在这些情况下,可以从win32 api使用GetModuleFileName

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

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

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

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

  • 简单应用程序
  • 在另一个域中,assembly.getEntryassembly()将返回空值
  • dll作为字节数组从嵌入资源加载,并作为程序集加载到AppDomain。加载(BytearrayOfEmbeddedDll)

1
AppDomain.CurrentDomain.BaseDirectory

将解决使用安装包引用第三方参考文件的问题。


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

因此可以使用queryfullprocessimagename来绕过这个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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) + @"";
    }
}

尝试以下简单代码行:

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

您可以使用以下代码,将获得应用程序完整路径:

1
2
3
4
5
6
7
8
9
10
11
 class Program
{
    static void Main(string[] args)
    {
        string AppPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
        WriteLine($"ApplicationPath ---{AppPath}");
        //OutPut// //ApplicationPath---C:\Users\TestUser\source
epos\ThreadStack\ThreadStack\bin\Debug\ThreadStack.exe
        ReadLine();
    }
}

我没有看到任何人将.NET核心反射提供的localpath转换为可用的system.io路径,所以这里是我的版本。

1
2
3
4
5
6
7
8
public static string GetApplicationRoot()
{
   var exePath = new Uri(System.Reflection.
   Assembly.GetExecutingAssembly().CodeBase).LocalPath;

   return new FileInfo(exePath).DirectoryName;

}

这将返回代码所在位置的完整"C:XXXXXX"格式路径。


有很多方法可以获得可执行路径,我们应该使用哪一个,这取决于我们的需要这里有一个链接,讨论不同的方法。

获取应用程序可执行路径的不同方法


这是一个可靠的解决方案,适用于32位和64位应用程序。

添加这些引用:

using System.Diagnostics;

using System.Management;

将此方法添加到项目中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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;
}

现在就这样使用:

1
2
3
int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

注意,如果您知道进程的ID,那么这个方法将返回相应的ExecutePath。

额外,对于感兴趣的人:

1
Process.GetProcesses()

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

1
Process.GetCurrentProcess()

…将为您提供当前进程,以及它们的信息(如ID等),以及有限的控制(如杀戮等)。*


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

1
2
3
4
5
6
7
8
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);
}