Как я могу получить путь к приложению в консольном приложении.NET?
Как найти путь к приложению в консольном приложении?
В Windows Forms я могу использовать Application.StartupPath
найти текущий путь, но он не доступен в консольном приложении.
33 ответа
System.Reflection.Assembly.GetExecutingAssembly()
, Location
1
Объедините это с System.IO.Path.GetDirectoryName
если все, что вы хотите, это каталог.
1 Согласно комментарию г-на Миндора:
System.Reflection.Assembly.GetExecutingAssembly().Location
возвращает, где находится исполняемая сборка, которая может быть, а может и не быть, где находится сборка, когда не выполняется. В случае теневых копий сборок вы получите путь во временный каталог.System.Reflection.Assembly.GetExecutingAssembly().CodeBase
вернет "постоянный" путь сборки.
Вы можете использовать следующий код, чтобы получить текущий каталог приложения.
AppDomain.CurrentDomain.BaseDirectory
У вас есть два варианта поиска каталога приложения, которое вы выберете, будет зависеть от вашей цели.
// 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);
Возможно, немного поздно, но это стоит упомянуть:
Environment.GetCommandLineArgs()[0];
Или правильнее получить только путь к каталогу:
System.IO.Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]);
Редактировать:
Довольно много людей отметили, что GetCommandLineArgs
не гарантируется возвращение имени программы. См . Первое слово в командной строке - это имя программы только по соглашению. В статье утверждается, что "Хотя очень немногие программы для Windows используют эту причуду (я сам о себе не знаю)". Так что можно "подделать" GetCommandLineArgs
, но мы говорим о консольном приложении. Консольные приложения обычно бывают быстрыми и грязными. Так что это соответствует моей философии KISS.
Для всех, кто интересуется веб-приложениями asp.net. Вот мои результаты 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", поэтому первое решение определенно не подходит для веб-приложений.
Ответ выше был на 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;
Если вы ищете.NET Core совместимый способ, используйте
System.AppContext.BaseDirectory
Это было представлено в.NET Framework 4.6 и.NET Core 1.0 (и.NET Standard 1.3). См.: Свойство AppContext.BaseDirectory.
Согласно этой странице,
Это предпочтительная замена для AppDomain.CurrentDomain.BaseDirectory в.NET Core
Возможно, вы хотите сделать это:
System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)
Вы можете использовать это вместо этого.
System.Environment.CurrentDirectory
Для консольных приложений вы можете попробовать это:
System.IO.Directory.GetCurrentDirectory();
Вывод (на моей локальной машине):
c: \ users \ xxxxxxx \ Documents\visual studio 2012\ Проекты \ImageHandler\GetDir\bin\Debug
Или вы можете попробовать (в конце есть дополнительная обратная косая черта):
AppDomain.CurrentDomain.BaseDirectory
Выход:
c: \ users \ xxxxxxx \ Documents\visual studio 2012\ Проекты \ImageHandler\GetDir\bin\Debug\
Я использовал этот код и получил решение.
AppDomain.CurrentDomain.BaseDirectory
Следующая строка даст вам путь к приложению:
var applicationPath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName)
Вышеупомянутое решение работает должным образом в следующих ситуациях:
- простое приложение
- в другом домене, где Assembly.GetEntryAssembly() будет возвращать ноль
- DLL загружается из встроенных ресурсов как байтовый массив и загружается в AppDomain как Assembly.Load(byteArrayOfEmbeddedDll)
Вы можете просто добавить в свой проект ссылки System.Windows.Forms
а затем использовать System.Windows.Forms.Application.StartupPath
по-прежнему.
Таким образом, не нужно более сложных методов или использования отражения.
Я использовал
System.AppDomain.CurrentDomain.BaseDirectory
когда я хочу найти путь относительно папки приложений. Это работает как для ASP.Net, так и для приложений winform. Также не требуется никаких ссылок на сборки System.Web.
Я имею в виду, почему не метод a 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");
Я не видел, чтобы кто-то преобразовывал LocalPath, предоставленный отражением.Net Core, в пригодный для использования путь System.IO, так что вот моя версия.
public static string GetApplicationRoot()
{
var exePath = new Uri(System.Reflection.
Assembly.GetExecutingAssembly().CodeBase).LocalPath;
return new FileInfo(exePath).DirectoryName;
}
Это вернет полный путь в формате "C:\xxx\xxx" туда, где находится ваш код.
Я использую это, если предполагается, что exe-файл вызывается двойным щелчком
var thisPath = System.IO.Directory.GetCurrentDirectory();
Для .NET 6 есть Environment.ProcessPath.
См. https://docs.microsoft.com/en-us/dotnet/api/system.environment.processpath?view=net-6.0 .
Assembly.GetEntryAssembly().Location
или же Assembly.GetExecutingAssembly().Location
Используйте в сочетании с System.IO.Path.GetDirectoryName()
чтобы получить только каталог.
Пути из GetEntryAssembly()
а также GetExecutingAssembly()
может отличаться, хотя в большинстве случаев каталог будет одинаковым.
С GetEntryAssembly()
Вы должны знать, что это может вернуть null
если модуль ввода неуправляемый (т.е. исполняемый файл C++ или VB6). В этих случаях можно использовать GetModuleFileName
из Win32 API:
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
public static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
В VB.net
My.Application.Info.DirectoryPath
у меня работает (Тип приложения: Библиотека классов). Не уверен насчет C#... Возвращает путь без имени файла в виде строки
С .NET Core 3 и выше вы получите DLL-файл, а не EXE-файл. Чтобы получить путь к файлу .exe, вы можете использовать.
var appExePath = Process.GetCurrentProcess().MainModule.FileName;
AppDomain.CurrentDomain.BaseDirectory
Решит проблему, ссылаясь на сторонние справочные файлы с установочными пакетами.
Попробуйте эту простую строку кода:
string exePath = Path.GetDirectoryName( Application.ExecutablePath);
В .NET 6 мое приложение WPF (<TargetFramework>net6.0-windows</TargetFramework>
) возвращает.dll
путь к файлу дляAssembly.GetEntryAssembly()!.Location
вместо.exe
файл. Они представилиSystem.Environment.ProcessPath
для этой цели:
var path = Environment.ProcessPath; // Note it may be null
Возвращает путь к исполняемому файлу, запустившему текущий исполняемый процесс. Возвращает
null
когда путь недоступен.
Ни один из этих методов не работает в особых случаях, таких как использование символической ссылки на исполняемый файл, они возвращают местоположение ссылки, а не фактический исполняемый файл.
Поэтому можно использовать 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) + @"\";
}
}
Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) - единственный, который работал у меня во всех случаях, которые я пробовал.
Техники и подводные камни постоянно меняются. Ниже предполагается, что вы используете консольное приложение .NET 6 в Linux (в 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/
У каждого подхода есть свои плюсы и минусы — см. другие ответы, чтобы узнать, в каких случаях использовать какой подход.
Я запускаю свое консольное приложение .NET 6 с помощьюdotnet myapp
, поэтому то, что работает (надежно) для меня, это одно из:
typeof(SomeType).Assembly.Location
// or
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
Другое решение - использовать относительные пути, указывающие на текущий путь:
Path.GetFullPath(".")
Вы можете использовать следующий код, вы получите полный путь к приложению:
class Program
{
static void Main(string[] args)
{
string AppPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
WriteLine($"ApplicationPath ---{AppPath}");
//OutPut// //ApplicationPath---C:\Users\TestUser\source\repos\ThreadStack\ThreadStack\bin\Debug\ThreadStack.exe
ReadLine();
}
}
Есть много способов получить путь к исполняемому файлу, который мы должны использовать, это зависит от наших потребностей. Вот ссылка, которая обсуждает различные методы.