Bir .NET konsol uygulamasında uygulamanın yolunu nasıl alabilirim?


953

Konsol uygulamasında uygulamanın yolunu nasıl bulurum?

In Windows Forms , ben kullanabilirsiniz Application.StartupPathgeçerli yolu bulmak için, ama bu bir konsol uygulamasında kullanılabilir olmasını görünmüyor.


5
.NET Framework'ü hedef (İstemci, Geliştirme) makinesine yüklüyor musunuz? cevabınız doğruysa; Böylece, System.Windows.Forms.dll dosyasına bir başvuru ekleyebilir ve Application.StartupPath! Gelecekteki istisnaları bırakmak istiyorsanız en iyi yol budur!
Ehsan Mohammadi

AppDomain.BaseDirectory, uygulama dizinidir. Uygulama VS env ve Win env farklı davranabileceğini unutmayın. Ancak AppDomain application.path ile aynı olmamalıdır, ancak bunun yalnızca IIS için olmadığını umarım.
Mertuarez

Yanıtlar:


1179

System.Reflection.Assembly.GetExecutingAssembly().Location1

System.IO.Path.GetDirectoryNameİstediğiniz tek şey dizinse ile birleştirin .

1 Mr.Mindor'un yorumuna göre: Yürütme
System.Reflection.Assembly.GetExecutingAssembly().Location derlemesinin şu anda bulunduğu yeri döndürür; yürütme sırasında derlemenin bulunduğu yer olabilir veya olmayabilir. Gölge kopyalama derlemeleri durumunda, geçici bir dizinde bir yol alırsınız. System.Reflection.Assembly.GetExecutingAssembly().CodeBasemontajın 'kalıcı' yolunu döndürür.


243
System.Reflection.Assembly.GetExecutingAssembly (). Konum, yürütme derlemesinin şu anda bulunduğu yere döner; yürütme sırasında derlemenin bulunduğu yer olabilir ya da olmayabilir. Gölge kopyalama derlemeleri durumunda, geçici bir dizinde bir yol alırsınız. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase , derlemenin ' permenant ' yolunu döndürür .
Mr.Mindor

13
@SamGoldberg: Bu, nasıl kullanıldığına bağlıdır: stackoverflow.com/q/1068420/391656 . Veya yeni Uri (System.Reflection.Assembly.GetExecutingAssembly (). CodeBase) .LocalPath
Mr.Mindor

28
GetExecutingAssemblyyürütülmekte olan kodu içeren derleme döndürür . Bu mutlaka konsol .exe derlemesi olmayabilir . Tamamen farklı bir yerden yüklenmiş bir montaj olabilir. Kullanmanız gerekecek GetEntryAssembly! Ayrıca CodeBasemontaj GAC'deyken ayarlanamayabileceğini unutmayın . Daha iyi bir alternatif AppDomain.CurrentDomain.BaseDirectory.
bitbonk

3
Kopyalamak rahat olması için lütfen 4
boşlukta


407

Geçerli uygulama dizinini almak için aşağıdaki kodu kullanabilirsiniz.

AppDomain.CurrentDomain.BaseDirectory

43
Bunu kullanma. BaseDirectory çalışma zamanında ayarlanabilir. Doğru olduğu garanti edilmez (kabul edilen cevap gibi).
usr

3
+1 Bu muhtemelen gölge kopyalamayı telafi ettiği için istediğiniz yanıttır.
George Mauer

4
@usr Bunun BaseDirectoryçalışma zamanında ayarlanabileceğini düşündüren nedir ? Sadece bir alıcı var.
bitbonk

3
@bitbonk, appdomain oluşturma zamanında ayarlanabilir.
usr

3
BaseDirectory bir ".lnk dosyasında," Başlama yeri: "alanında değiştirilemez mi?
Alexander

170

Uygulamanın dizinini bulmak için iki seçeneğiniz vardır; seçtiğiniz dizin amacınıza bağlıdır.

// 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
Sadece söylemek istedim, belli ki kaç seçenek daha yayınlanmıştır tarafından 2'den fazla seçenek var ...
vapcguy

17
Bahsedilen yolla yapmaya çalıştığınız her şey URI biçimini desteklemiyorsa, kullanınvar localDirectory = new Uri(directory).LocalPath;
Scott Solmer

Bu sadece yanlış. Yürütülebilir dosya hiç bir .NET derleme değil nedir? Doğru cevap, çevreyi kontrol etmek ve komut satırını incelemek.
mark

@ Ukuma.Scott Bu yol & veya # içeriyorsa çalışmaz
MatsW

82

Muhtemelen biraz geç ama bu bir kayda değer:

Environment.GetCommandLineArgs()[0];

Veya sadece dizin yolunu almak için daha doğru:

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

Düzenle:

Oldukça az sayıda kişi GetCommandLineArgs, program adını döndürmenin garanti edilmediğine dikkat çekti . Bkz komut satırında ilk kelimeyi sadece Kongre tarafından programın adıdır . Makale, "Çok az sayıda Windows programı bu tuhaflığı kullanmasına rağmen (kendimin farkında değilim)" yazıyor. Bu yüzden 'parodi' yapmak mümkündür GetCommandLineArgs, ancak bir konsol uygulamasından bahsediyoruz. Konsol uygulamaları genellikle hızlı ve kirlidir. Bu benim KISS felsefeme uyuyor.


1
@usr, bahsettiğiniz durum oldukça teorik. Bir konsol uygulaması bağlamında, başka bir yöntem kullanmak gerçekten mantıklı değildir. Basit tutun!
Steve Mc

1
@usr mmm - taskmgr cmdline sütununa baktığımda söylediklerimi destekliyor. Sadece exe adı ile birkaç sistem hizmetleri. Boşver. Söylemeye çalıştığım şey, bir konsol uygulaması geliştirirken, işleri olması gerekenden daha karmaşık hale getirmeye gerek olmadığıdır. Özellikle de elimizdeki bilgilere sahip olduğumuzda. Şimdi, GetCommandLineArgs'ı kandırmak için bir konsol uygulaması çalıştırıyorsanız, o zaman zaten çemberlerden atlıyorsunuz ve muhtemelen kendinize bir konsol uygulamasının doğru yol olup olmadığını sormanız gerekir.
Steve Mc

5
"Basit" çözümünüz iki yöntem çağrısı içerir. "Karmaşık" çözüm iki yöntem çağrısı içerir. Pratik bir fark yok - "basit" çözüm, programı yazarken kontrolünüz altında olmayan belirli koşullar altında size yanlış cevap verebilir. Neden risk almalı? Diğer iki yöntem çağrısını kullanın, programınız daha karmaşık olmayacak, ancak daha güvenilir olacaktır.
Chris

3
Benim senaryo için çalıştı, diğer çözümler vermedi, bu yüzden başka bir alternatif sağladığınız için teşekkürler :-) Bir MS Unit testi çalıştırmak için ReSharper test runner kullanıyordum ve ben test kod belirli bir .dll yürütme dizininde olması gerekiyordu. ..ve Assembly.GetExecutingDirectory () garip bir şekilde farklı bir sonuç döndürüyor.
wallismark

1
@Chris - bu cevabın savunmasına. Birim testleri için çalışır, GetEntryAssembly çözümü çalışmaz, çünkü GetEntryAssembly null değerini döndürür. GetExecutingAssembly öneren yanıtlar sahte, çünkü çalıştırılabilir derleme yalnızca çalıştırılabilir derleme yürütülebilir ise. Bu basit değil, doğru çözümdür.
mark

44

Asp.net web uygulamaları ile ilgilenen herkes için. İşte 3 farklı yöntemin sonuçları

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);
}

sonuç

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

uygulama fiziksel olarak "C: \ inetpub \ SBSPortal_staging" ile çalışıyor, bu nedenle ilk çözüm kesinlikle web uygulamaları için uygun değil.


42

Yukarıdaki cevap ihtiyacım olanın% 90'ıydı, ama benim için düzenli bir yol yerine bir Uri döndürdü.

MSDN forumları postasında açıklandığı gibi, URI yolu normal dosyayoluna nasıl dönüştürülür? , Aşağıdakileri kullandım:

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

1
söz konusu exe bir Windows hizmeti ve geçerli dizin C: \ Windows \ system32 döndürürse de bu iyi çalışır. Yukarıdaki kod
exe'nin

Sonra böyle bir şey yapmaya çalışırsanız File.CreateDirectory(path), bu size URI yollarına izin vermediği istisnasını verecektir ...
vapcguy

1
Ne yazık ki bu bir parça tanımlayıcısı ( #karakter) içeren yollar için geçerli değildir . Tanımlayıcı ve onu izleyen her şey elde edilen yoldan kesilir.
bgfvdu3w

Neden takas etmiyorsun new Urive System.IO.Path.GetDirectoryName? Bu size a yerine normal bir yol dizesi verir Uri.
Timo

Bunu en iyi buluyorum. Aynı yaklaşım benim için her ortamda güvenilir bir şekilde çalıştı. Üretimde, yerel olarak hata ayıklama, birim testi ... Birim testine eklediğiniz bir içerik dosyasını ("içerik - daha yeniyse kopyala") açmak ister misiniz? Orada.
Timo

29

Bunu yapmak istiyor olabilirsiniz:

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

23

bunun yerine bunu kullanabilirsiniz.

System.Environment.CurrentDirectory

Bu, yürütülebilir dosyanın klasörünü alacak
Iain

Bu, çeşitli şekillerde değiştirilebilir (kısayol ayarları vb.) ... KULLANMAMASI daha iyi.
Yousha Aleayoub

23

.NET Core uyumlu bir yol arıyorsanız,

System.AppContext.BaseDirectory

Bu, .NET Framework 4.6 ve .NET Core 1.0'da (ve .NET Standard 1.3'te) tanıtıldı. Bkz . AppContext.BaseDirectory Özelliği .

Bu sayfaya göre ,

Bu, .NET Core'da AppDomain.CurrentDomain.BaseDirectory için tercih edilen yedek


1
bağımsız dotnet konsolu uygulamaları için ayrıca github.com/dotnet/runtime/issues/13051 adresine bakın . Buradaki tavsiye kullanmaktırProcess.GetCurrentProcess().MainModule.FileName
Gavin

19

Konsol Uygulamaları için şunu deneyebilirsiniz:

System.IO.Directory.GetCurrentDirectory();

Çıktı (yerel makinemde):

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

Ya da deneyebilirsiniz (sonunda ek bir ters eğik çizgi var):

AppDomain.CurrentDomain.BaseDirectory

Çıktı:

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


"Çalışma BaseDirectoryzamanında ayarlanabilir. Doğru olması garanti EDİLMEZ"
Yousha Aleayoub


9

Proje referanslarınıza ekleyebilir System.Windows.Formsve ardındanSystem.Windows.Forms.Application.StartupPath her zamanki gibi .

Bu nedenle, daha karmaşık yöntemlere veya yansımayı kullanmaya gerek yoktur.


Bunu kullandım ve iyi çalışıyor. Ama bir keresinde birim test projemde bu yöntemi kullandım. Ve elbette, C: \ PROGRAM FILES (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW
ainasiart

@ainasiart Peki bu birim test ederken işe nasıl alabilirim?
Nicholas Siegmundt

8

Aşağıdaki satır size bir uygulama yolu verecektir:

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

Yukarıdaki çözüm aşağıdaki durumlarda düzgün çalışıyor:

  • basit uygulama
  • Assembly.GetEntryAssembly () öğesinin null döndüreceği başka bir etki alanında
  • DLL, Gömülü kaynaklardan bir bayt dizisi olarak yüklenir ve AppDomain'e Assembly.Load (byteArrayOfEmbeddedDll) olarak yüklenir
  • Mono'nun mkbundledemetleri ile (başka yöntem işe yaramıyor)

Linux hata ayıklayıcı altında bu döndürür: / usr / share / dotnet
Vladimir

7

Eğer exe çift tıklayarak çağrılması gerekiyorsa bunu kullanıyorum

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

5
Sonuçta rastgele dizinler alabileceğiniz için bu doğru değildir.
amuliar

bu Komut çalışma zamanında herhangi bir yola değiştirilebilecek Environment.CurrentDirectory öğesini döndürür, bu nedenle güvenilir bir çözüm değildir.
Yury Kozlov

7

Kullandım

System.AppDomain.CurrentDomain.BaseDirectory

uygulamalar klasörüne göre bir yol bulmak istediğimde. Bu hem ASP.Net hem de winform uygulamaları için geçerlidir. Ayrıca System.Web derlemelerine başvuru gerektirmez.


6

Yani, ap / invoke yöntemi neden olmasın?

    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());
                }
            }
    }

Tıpkı Application.tartupPath gibi kullanırsınız:

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

2
Bunun için çok fazla .NET olduğunda neden p / invoke?
ProfK

7
@ user3596865 çünkü Windows'a büyük bir bağımlılık gerektirir ve DNX veya Mono ile uyumlu değildir. Ve belki de gelecekteki Windows Sürümlerinde büyük bir değişiklik var. Peki yine: neden pinvoke kullanmalıyız?
Ben

5

Assembly.GetEntryAssembly().Location veya Assembly.GetExecutingAssembly().Location

System.IO.Path.GetDirectoryName()Yalnızca dizini almak için ile birlikte kullanın .

Çoğu durumda dizin aynı olsa da, yollar GetEntryAssembly()ve GetExecutingAssembly()farklı olabilir.

Bununla birlikte , giriş modülü yönetilmezse (örn. C ++ veya VB6 yürütülebilir) GetEntryAssembly()bunun geri dönebileceğini bilmelisiniz null. Bu gibi durumlarda GetModuleFileNameWin32 API'den kullanmak mümkündür :

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

5

VB.net'te

My.Application.Info.DirectoryPath

benim için çalışıyor (Uygulama Türü: Sınıf Kütüphanesi). C # hakkında emin değilim ... Dosyaadı olmayan yolu dize olarak döndürür


4
AppDomain.CurrentDomain.BaseDirectory

Yükleme paketleriyle birlikte 3. taraf referans dosyalarına başvurma sorununu çözecektir.


11
Bu cevap zaten 5 yıl önce, bir kereden fazla bile önerildi.
PL

2

Bu yöntemlerin hiçbiri exe'ye sembolik bir bağlantı kullanmak gibi özel durumlarda işe yaramaz, gerçek exe'ye değil bağlantının konumunu döndürürler.

Bunu yapmak için QueryFullProcessImageName kullanabilirsiniz :

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

Bu basit kod satırını deneyin:

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

1

Başka bir çözüm, geçerli yolu gösteren göreli yollar kullanmaktır:

Path.GetFullPath(".")

Bu, başlangıç ​​dizininin yerini değil, geçerli dizini alır.
tenfour

0

.Net Core yansıması tarafından sağlanan LocalPath'i kullanılabilir bir System.IO yoluna dönüştüren kimseyi görmedim, işte sürümüm.

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

   return new FileInfo(exePath).DirectoryName;

}

Bu, kodunuzun bulunduğu yere "C: \ xxx \ xxx" biçimli yolun tamamını döndürür.



-1

İşte 32bit ve 64bit uygulamalarla çalışan güvenilir bir çözüm .

Bu referansları ekleyin:

System.Diagnostics kullanarak;

System.Management kullanarak;

Bu yöntemi projenize ekleyin:

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;
}

Şimdi şöyle kullanın:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

İşlemin kimliğini biliyorsanız, bu yöntemin karşılık gelen ExecutePath değerini döndüreceğini unutmayın.

Ekstra, ilgilenenler için:

Process.GetProcesses() 

... şu anda çalışan tüm işlemlerin bir dizisini verecek ve ...

Process.GetCurrentProcess()

... mevcut süreçle birlikte bilgileri, örneğin Kimlik, vb. ve ayrıca sınırlı kontrol, örneğin Öldür, vb.


-5

Solution Explorer'ı kullanarak proje içinde Kaynaklar olarak bir klasör adı oluşturabilir, ardından Kaynaklar'ın içine bir dosya yapıştırabilirsiniz.

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 kullanımı çok yanlış, bunu kullanmayın! bu yol çalışma zamanında değişebilir. Başlangıçta bile belirleyici değildir.
usr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.