Come posso ottenere il percorso dell'applicazione in un'applicazione console .NET?


953

Come trovo il percorso dell'applicazione in un'applicazione console?

In Windows Form , posso usare Application.StartupPathper trovare il percorso corrente, ma questo non sembra essere disponibile in un'applicazione console.


5
Installa .NET Framework sul computer di destinazione (client, sviluppo)? se la tua risposta è vera; Quindi, puoi aggiungere un riferimento a System.Windows.Forms.dll e utilizzare Application.StartupPath! Questo è il modo migliore se si desidera eliminare ulteriori eccezioni future!
Ehsan Mohammadi,

AppDomain.BaseDirectory è la directory dell'app. Tenere presente che l'applicazione può comportarsi diversamente in VS env e Win env. Ma AppDomain dovrebbe essere uguale a application.path ma spero che questo non sia solo per IIS.
Mertuarez,

Risposte:


1179

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

Combina questo con System.IO.Path.GetDirectoryNamese tutto ciò che vuoi è la directory.

1 Secondo il commento di Mr.Mindor:
System.Reflection.Assembly.GetExecutingAssembly().Location restituisce dove si trova l'assembly in esecuzione, che può essere o meno dove si trova l'assembly quando non viene eseguito. Nel caso di assiemi di copie shadow, si otterrà un percorso in una directory temporanea. System.Reflection.Assembly.GetExecutingAssembly().CodeBaserestituirà il percorso 'permanente' dell'assemblaggio.


243
System.Reflection.Assembly.GetExecutingAssembly (). Ritorna posizione in cui l'esecuzione di montaggio è attualmente posizionato, che possono o non possono essere dove si trova l'assembly quando non è in esecuzione. Nel caso di assiemi di copie shadow, si otterrà un percorso in una directory temporanea. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase restituirà il percorso ' permenant ' dell'assembly.
Mr.Mindor,

13
@SamGoldberg: dipende da come viene utilizzato: stackoverflow.com/q/1068420/391656 . Oppure puoi ... new Uri (System.Reflection.Assembly.GetExecutingAssembly (). CodeBase) .LocalPath
Mr.Mindor

28
GetExecutingAssemblyrestituisce un assembly che contiene il codice attualmente in esecuzione . Questo potrebbe non essere necessariamente l' assembly .exe della console . Potrebbe essere un assieme che è stato caricato da una posizione completamente diversa. Dovrai usare GetEntryAssembly! Si noti inoltre che CodeBasepotrebbe non essere impostato quando l'assembly si trova nel GAC. L'alternativa migliore è AppDomain.CurrentDomain.BaseDirectory.
Bitbonk,

3
Si prega di scrivere il codice in 4 spazi in modo che sia comodo da copiare
fnc12

3
se chiamate dll, System.Reflection.Assembly.GetExecutingAssembly (). CodeBase otterrà "file: /// C: /Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
raidsan

407

È possibile utilizzare il seguente codice per ottenere la directory dell'applicazione corrente.

AppDomain.CurrentDomain.BaseDirectory

43
Non usare questo. BaseDirectory può essere impostato in fase di esecuzione. Non è garantito che sia corretto (come la risposta accettata è).
usr

3
+1 Questa è probabilmente la risposta che desideri in quanto compensa la copia shadow.
George Mauer,

4
@usr Cosa ti fa pensare che BaseDirectorypossa essere impostato in fase di esecuzione? Ha solo un getter.
Bitbonk,

3
@bitbonk può essere impostato al momento della creazione dell'appdomain.
usr

3
BaseDirectory non può essere modificato in un file * .lnk, nel campo "Inizia tra:"?
Alexander,

170

Hai due opzioni per trovare la directory dell'applicazione, che sceglierai dipenderà dal tuo scopo.

// 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
Volevo solo dire, ovviamente ci sono molte più di 2 opzioni in base a quante altre opzioni sono pubblicate ...
vapcguy

17
Se qualunque cosa tu stia cercando di fare con detto percorso non supporta il formato URI, usavar localDirectory = new Uri(directory).LocalPath;
Scott Solmer il

Questo è semplicemente sbagliato. Cos'è l'eseguibile non è affatto un assembly .NET? La risposta giusta è controllare l'ambiente e ispezionare la riga di comando.
segna il

@ Ukuma.Scott Questo non funziona se il percorso contiene & o #
MatsW

82

Probabilmente un po 'in ritardo, ma vale la pena menzionare:

Environment.GetCommandLineArgs()[0];

O più correttamente per ottenere solo il percorso della directory:

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

Modificare:

Molte persone hanno sottolineato che GetCommandLineArgsnon è garantito il ritorno del nome del programma. Vedere La prima parola nella riga di comando è il nome del programma solo per convenzione . L'articolo afferma che "Sebbene estremamente pochi programmi Windows utilizzino questa stranezza (non ne sono a conoscenza da solo)". Quindi è possibile "spoofare" GetCommandLineArgs, ma stiamo parlando di un'applicazione console. Le app della console sono in genere veloci e sporche. Quindi questo si adatta alla mia filosofia KISS.


1
@usr la situazione a cui alludi è altamente teorica. Nel contesto di un'applicazione console, non ha davvero senso utilizzare nessun altro metodo. Mantienilo semplice!
Steve Mc

1
@usr mmm - guardando la colonna cmdline taskmgr fa una specie di backup di ciò che sto dicendo. Alcuni servizi di sistema con solo il nome exe. Non importa. Quello che sto cercando di dire è che quando si sviluppa un'applicazione console non è necessario rendere le cose più complicate di quanto debbano essere. Soprattutto quando disponiamo già delle informazioni disponibili. Ora, se stai eseguendo un'applicazione console in modo da ingannare GetCommandLineArgs, allora stai già saltando attraverso i cerchi e probabilmente dovrai chiederti se un'app console è la strada giusta da percorrere.
Steve Mc

5
La tua soluzione "semplice" prevede due chiamate di metodo. La soluzione "complicata" prevede due chiamate di metodo. Nessuna differenza pratica - tranne che la soluzione "semplice" può darti la risposta sbagliata in determinate circostanze che non sono sotto il tuo controllo durante la scrittura del programma. Perché correre il rischio? Usa le altre due chiamate di metodo e il tuo programma non sarà più complicato ma sarà più affidabile.
Chris,

3
Ha funzionato per il mio scenario, le altre soluzioni no, quindi grazie per aver fornito un'altra alternativa :-) Stavo usando ReSharper test runner per eseguire un test di unità MS e il codice che stavo testando aveva bisogno di un .dll specifico per trovarsi nella directory di esecuzione. ..and Assembly.GetExecutingDirectory () restituisce in modo strano un risultato diverso.
wallismark

1
@Chris - a difesa di questa risposta. Funziona per unit test, la soluzione GetEntryAssembly no, perché GetEntryAssembly restituisce null. Le risposte che propongono GetExecutingAssembly sono false, perché restituiscono l'eseguibile solo se l'assembly in esecuzione è l'eseguibile. Questa non è la soluzione semplice, ma corretta.
segna il

44

Per chiunque sia interessato alle app web asp.net. Ecco i miei risultati di 3 metodi diversi

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

risultato

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

l'app è fisicamente in esecuzione da "C: \ inetpub \ SBSPortal_staging", quindi la prima soluzione non è assolutamente appropriata per le app Web.


42

La risposta sopra era il 90% di ciò di cui avevo bisogno, ma mi ha restituito un Uri invece di un percorso regolare per me.

Come spiegato nel post del forum MSDN, Come convertire il percorso URI in normale percorso file? , Ho usato il seguente:

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

1
funziona bene anche se l'exe in questione è un servizio Windows e la directory corrente restituisce C: \ Windows \ system32. Il codice sopra riportato restituisce l'effettiva posizione
dell'exe

Tranne se poi provi a fare qualcosa del genere File.CreateDirectory(path), ti darà l'eccezione che non consente i percorsi URI ...
vapcguy

1
Purtroppo questo non funziona per i percorsi che contengono un identificatore di frammento (il #carattere). L'identificatore e tutto ciò che lo segue viene troncato dal percorso risultante.
bgfvdu3w,

Perché non si scambia new Urie System.IO.Path.GetDirectoryName? Questo ti dà una normale stringa di percorso invece di a Uri.
Timo,

Lo trovo il migliore. Questo stesso approccio ha funzionato in modo affidabile per me in qualsiasi ambiente. In produzione, debug a livello locale, unit test ... Vuoi aprire un file di contenuto che hai incluso ("content - copy if newer") in un unit test? È lì.
Timo,

29

Potresti voler fare questo:

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

23

puoi usare questo invece.

System.Environment.CurrentDirectory

Questo otterrà la cartella dell'eseguibile
Iain

Questo può essere modificato in vari modi (impostazioni di scelta rapida, ecc.) ... meglio NON utilizzarlo.
Yousha Aleayoub,

23

Se stai cercando un modo compatibile con .NET Core, usa

System.AppContext.BaseDirectory

Questo è stato introdotto in .NET Framework 4.6 e .NET Core 1.0 (e .NET Standard 1.3). Vedi: Proprietà AppContext.BaseDirectory .

Secondo questa pagina ,

Questa è la sostituzione preferita per AppDomain.CurrentDomain.BaseDirectory in .NET Core


1
vedi anche github.com/dotnet/runtime/issues/13051 per le app console dotnet indipendenti. La raccomandazione qui è di usareProcess.GetCurrentProcess().MainModule.FileName
Gavin

19

Per le applicazioni console, puoi provare questo:

System.IO.Directory.GetCurrentDirectory();

Uscita (sul mio computer locale):

c: \ utenti \ xxxxxxx \ documenti \ visual studio 2012 \ Progetti \ ImageHandler \ GetDir \ bin \ Debug

Oppure puoi provare (c'è una barra rovesciata aggiuntiva alla fine):

AppDomain.CurrentDomain.BaseDirectory

Produzione:

c: \ utenti \ xxxxxxx \ documenti \ visual studio 2012 \ Progetti \ ImageHandler \ GetDir \ bin \ Debug \


" BaseDirectoryPuò essere impostato in fase di esecuzione. NON è garantito che sia corretto"
Yousha Aleayoub


9

Puoi semplicemente aggiungere ai riferimenti del tuo progetto System.Windows.Formse quindi utilizzare il System.Windows.Forms.Application.StartupPath solito.

Quindi, non è necessario per metodi più complicati o usando la riflessione.


L'ho usato e funziona bene. Ma una volta ho usato il metodo nel mio progetto di unit test. E, naturalmente, fallì perché stava cercando il mio file in C: \ PROGRAM FILES (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW
ainasiart

@ainasiart, quindi come posso farlo funzionare durante i test unitari ??
Nicholas Siegmundt il

8

La seguente riga fornisce un percorso dell'applicazione:

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

La soluzione sopra funziona correttamente nelle seguenti situazioni:

  • semplice app
  • in un altro dominio in cui Assembly.GetEntryAssembly () restituirebbe null
  • La DLL viene caricata dalle risorse integrate come array di byte e caricata in AppDomain come Assembly.Load (byteArrayOfEmbeddedDll)
  • con i mkbundlebundle di Mono (nessun altro metodo funziona)

Sotto debugger su Linux questo restituisce: / usr / share / dotnet
Vladimir

7

Lo uso se si suppone che l'exe venga chiamato facendo doppio clic su di esso

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

5
Ciò non è corretto perché è possibile ottenere directory casuali nel risultato.
amuliar

questo comando restituisce Environment.CurrentDirectory, che può essere modificato in fase di esecuzione su qualsiasi percorso, quindi non è una soluzione affidabile.
Yury Kozlov,

7

ho usato

System.AppDomain.CurrentDomain.BaseDirectory

quando voglio trovare un percorso relativo a una cartella di applicazioni. Funziona sia con ASP.Net che con applicazioni winform. Inoltre non richiede alcun riferimento agli assembly System.Web.


6

Voglio dire, perché non un metodo 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());
                }
            }
    }

Lo useresti proprio come Application.StartupPath:

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

2
Perché p / invoke quando c'è così tanto .NET per questo?
ProfK

7
@ user3596865 perché richiede una forte dipendenza da Windows e non è compatibile con DNX o Mono. E forse c'è un cambiamento radicale nelle future versioni di Windows. Quindi di nuovo: perché dovremmo usare pinvoke qui?
Ben

5

Assembly.GetEntryAssembly().Location o Assembly.GetExecutingAssembly().Location

Utilizzare in combinazione con System.IO.Path.GetDirectoryName()per ottenere solo la directory.

I percorsi da GetEntryAssembly()e GetExecutingAssembly()possono essere diversi, anche se nella maggior parte dei casi la directory sarà la stessa.

Con GetEntryAssembly()te devi essere consapevole che questo può tornare nullse il modulo di ingresso non è gestito (cioè eseguibile C ++ o VB6). In questi casi è possibile utilizzare GetModuleFileNamedall'API Win32:

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

5

in VB.net

My.Application.Info.DirectoryPath

funziona per me (Tipo di applicazione: Libreria di classi). Non sono sicuro di C # ... Restituisce il percorso senza Nome file come stringa


4
AppDomain.CurrentDomain.BaseDirectory

Risolverà il problema per fare riferimento ai file di riferimento di terze parti con i pacchetti di installazione.


11
Questa risposta è già stata suggerita 5 anni fa, anche più di una volta.
PL

2

Nessuno di questi metodi funziona in casi speciali come l'uso di un collegamento simbolico con l'exe, restituiranno la posizione del collegamento non l'exe effettivo.

Quindi puoi usare QueryFullProcessImageName per aggirare questo:

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

Prova questa semplice riga di codice:

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

1

Un'altra soluzione sta usando percorsi relativi che puntano al percorso corrente:

Path.GetFullPath(".")

In questo modo si ottiene la directory corrente, non la posizione del file EXE iniziale.
tenfour

0

Non ho visto nessuno convertire il LocalPath fornito da .Net Core reflection in un percorso System.IO utilizzabile, quindi ecco la mia versione.

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

   return new FileInfo(exePath).DirectoryName;

}

Ciò restituirà il percorso completo "C: \ xxx \ xxx" formattato dove si trova il tuo codice.



-1

Ecco una soluzione affidabile che funziona con applicazioni a 32 e 64 bit .

Aggiungi questi riferimenti:

utilizzando System.Diagnostics;

utilizzando System.Management;

Aggiungi questo metodo al tuo progetto:

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

Ora usalo così:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Si noti che se si conosce l'id del processo, questo metodo restituirà ExecutePath corrispondente.

Extra, per chi è interessato:

Process.GetProcesses() 

... ti darà una serie di tutti i processi attualmente in esecuzione, e ...

Process.GetCurrentProcess()

... ti fornirà il processo corrente, insieme alle loro informazioni, ad esempio Id, ecc. e anche un controllo limitato, ad esempio Kill, ecc. *


-5

È possibile creare un nome di cartella come Risorse all'interno del progetto utilizzando Esplora soluzioni, quindi è possibile incollare un file all'interno delle Risorse.

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
Usare Environment.CurrentDirectory è molto sbagliato, non usarlo! questo percorso può cambiare in fase di esecuzione. Anche all'avvio non è deterministico.
usr
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.