如何在控制台应用程序中找到应用程序的路径?
在Windows窗体中,我可以使用应用程序。StartupPath来查找当前路径,但这在控制台应用程序中似乎不可用。
如何在控制台应用程序中找到应用程序的路径?
在Windows窗体中,我可以使用应用程序。StartupPath来查找当前路径,但这在控制台应用程序中似乎不可用。
.Location1 System.Reflection.Assembly.GetExecutingAssembly ()
如果你想要的只是目录,将它与System.IO.Path.GetDirectoryName结合起来。
根据minor先生的评论: System.Reflection.Assembly.GetExecutingAssembly()。Location返回正在执行的程序集当前所在的位置,该位置可能是也可能不是程序集未执行时所在的位置。在阴影复制程序集的情况下,您将获得临时目录中的路径。System.Reflection.Assembly.GetExecutingAssembly()。CodeBase将返回程序集的“永久”路径。
你可能会这样做:
System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)
可能有点晚了,但这个值得提一下:
Environment.GetCommandLineArgs()[0];
或者更准确地获取目录路径:
System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
编辑:
相当多的人已经指出GetCommandLineArgs并不能保证返回程序名。请参见命令行上的第一个单词只是按照约定的程序名。这篇文章确实指出“尽管很少有Windows程序使用这个怪癖(我自己不知道)”。因此,“恶搞”GetCommandLineArgs是可能的,但我们谈论的是一个控制台应用程序。控制台应用程序通常是快速和肮脏的。所以这符合我的KISS哲学。
编辑 从反馈来看,当您使用单元测试系统时,大多数其他解决方案似乎都不起作用。这是有道理的,因为可执行项不是你的应用程序,而是测试系统。我还没有核实过,所以我可能完全错了。如果是这样,我将删除这一编辑。
对于任何对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应用程序。
您有两个选项来查找应用程序的目录,具体选择哪个取决于您的目的。
// 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);
Assembly.GetEntryAssembly()。Location或Assembly.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);
上面的答案是我需要的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;
可以使用“解决方案资源管理器”在项目中创建文件夹名称为“资源”,然后可以在“资源”中粘贴文件。
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);
}
我使用这个如果exe被认为是通过双击它来调用
var thisPath = System.IO.Directory.GetCurrentDirectory();
我用过
System.AppDomain.CurrentDomain.BaseDirectory
当我想找到一个相对于应用程序文件夹的路径时。这适用于ASP。Net和winform应用程序。它也不需要任何对System的引用。Web组件。
对于控制台应用程序,您可以尝试这样做:
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\
为什么不是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());
}
}
}
您可以像使用应用程序一样使用它。StartupPath:
Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");
这里有一个可靠的解决方案,适用于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等,也有限制控制,如杀死等*
你可以简单地添加到你的项目引用System.Windows.Forms,然后像往常一样使用System.Windows.Forms. application . startuppath。
因此,不需要更复杂的方法或使用反射。
这些方法在特殊情况下都不起作用,比如使用到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) + @"\";
}
}
试试下面这行简单的代码:
string exePath = Path.GetDirectoryName( Application.ExecutablePath);
如果你正在寻找一种与。net Core兼容的方法,请使用
System.AppContext.BaseDirectory
这是在。net Framework 4.6和。net Core 1.0(和。net Standard 1.3)中引入的。看到:AppContext。BaseDirectory财产。
根据这一页,
这是。net Core中AppDomain.CurrentDomain.BaseDirectory的首选替代品
我没有看到任何人将. net Core反射提供的LocalPath转换为可用的系统。IO路径,这是我的版本。
public static string GetApplicationRoot()
{
var exePath = new Uri(System.Reflection.
Assembly.GetExecutingAssembly().CodeBase).LocalPath;
return new FileInfo(exePath).DirectoryName;
}
这将返回完整的C:\\xxx\\xxx格式的路径到您的代码所在的位置。
下面一行将给出应用程序路径:
var applicationPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)
上述解决方案在以下情况下正常工作:
简单的应用 在另一个域,Assembly.GetEntryAssembly()将返回null DLL以字节数组的形式从嵌入式资源加载,并以Assembly.Load的形式加载到AppDomain。 使用Mono的mkbundle bundles(没有其他方法工作)
Path.GetDirectoryName (System.Diagnostics.Process.GetCurrentProcess () .MainModule.FileName) 是唯一一个在我尝试过的所有案例中都有效的方法。
在。net Core 3及以上版本中,你会得到。dll文件而不是。exe文件。获取您可以使用的.exe文件路径。
var appExePath = Process.GetCurrentProcess().MainModule.FileName;
我将此用于console + net 6
Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)
对于。net 6,有Environment.ProcessPath。
见https://learn.microsoft.com/en - us/dotnet/api/system.environment.processpath?view=net 6.0
技术和陷阱一直在变化。下面假设你在linux上运行。net 6控制台应用程序(在win/mac上,结果将遵循类似的模式,只需将/usr/share/和/home/username/替换为操作系统的标准位置)。
演示:
Console.WriteLine("Path.GetDirectoryName(Process.GetCurrentProcess()?.MainModule?.FileName) = " + Path.GetDirectoryName(Process.GetCurrentProcess()?.MainModule?.FileName));
Console.WriteLine("Path.GetDirectoryName(Environment.ProcessPath) = " + Path.GetDirectoryName(Environment.ProcessPath));
Console.WriteLine("Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) = " + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
Console.WriteLine("typeof(SomeType).Assembly.Location = " + typeof(SomeType).Assembly.Location);
Console.WriteLine("Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) = " + Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]));
Console.WriteLine("AppDomain.CurrentDomain.BaseDirectory = " + AppDomain.CurrentDomain.BaseDirectory);
Console.WriteLine("System.AppContext.BaseDirectory = " + System.AppContext.BaseDirectory);
结果:
Path.GetDirectoryName(Process.GetCurrentProcess()?.MainModule?.FileName) = /usr/share/dotnet
Path.GetDirectoryName(Environment.ProcessPath) = /usr/share/dotnet
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) = /home/username/myproject/bin/Debug/net6.0
typeof(SomeType).Assembly.Location = /home/username/myproject/bin/Debug/net6.0
Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]) = /home/username/myproject/bin/Debug/net6.0
AppDomain.CurrentDomain.BaseDirectory = /home/username/myproject/bin/Debug/net6.0/
System.AppContext.BaseDirectory = /home/username/myproject/bin/Debug/net6.0/
每种方法都有其优点和缺点-请参阅其他答案以了解在哪种情况下使用哪种方法。
我用dotnet myapp运行我的.NET 6控制台应用程序,所以对我来说(可靠的)工作是:
typeof(SomeType).Assembly.Location
// or
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
在。net6中,我的WPF应用程序(<TargetFramework>net6.0-windows</TargetFramework>)返回Assembly.GetEntryAssembly()的.dll文件路径!位置,而不是。exe文件。他们引入了System.Environment.ProcessPath:
var path = Environment.ProcessPath; // Note it may be null
返回启动当前执行进程的可执行文件的路径。当路径不可用时返回null。
请参见这里和这里的讨论。