Comment puis-je obtenir le chemin de l'application dans une application de console .NET?

953

Comment trouver le chemin de l'application dans une application console?

Dans Windows Forms , je peux utiliser Application.StartupPathpour trouver le chemin actuel, mais cela ne semble pas être disponible dans une application console.

JSmyth
la source
5
Installez-vous .NET Framework sur la machine cible (client, développement)? si votre réponse est vraie; Ainsi, vous pouvez ajouter une référence à System.Windows.Forms.dll et utiliser Application.StartupPath! C'est le meilleur moyen si vous souhaitez supprimer d'autres exceptions futures!
Ehsan Mohammadi
AppDomain.BaseDirectory est le répertoire de l'application. Sachez que l'application peut se comporter différemment dans VS env et Win env. Mais AppDomain ne doit pas être identique à application.path mais j'espère que ce n'est pas seulement pour IIS.
Mertuarez

Réponses:

1179

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

Combinez cela avec System.IO.Path.GetDirectoryNamesi tout ce que vous voulez est le répertoire.

1 Selon le commentaire de M.Mindor:
System.Reflection.Assembly.GetExecutingAssembly().Location retourne où se trouve actuellement l'assemblage d'exécution, qui peut ou non être situé là où l'assemblage se trouve lorsqu'il n'est pas en cours d'exécution. Dans le cas des assemblys de copie miroir, vous obtiendrez un chemin dans un répertoire temporaire. System.Reflection.Assembly.GetExecutingAssembly().CodeBaseretournera le chemin «permanent» de l'assemblage.

Sam Axe
la source
243
System.Reflection.Assembly.GetExecutingAssembly (). Location renvoie l'endroit où se trouve actuellement l' assembly en cours d'exécution , qui peut être ou ne pas être situé en dehors de l'assembly. Dans le cas des assemblys de copie miroir, vous obtiendrez un chemin dans un répertoire temporaire. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase renverra le chemin d'accès permanent de l'assembly.
Mr.Mindor
13
@SamGoldberg: Cela dépend de la façon dont il est utilisé: stackoverflow.com/q/1068420/391656 . Ou vous pouvez ... nouveau Uri (System.Reflection.Assembly.GetExecutingAssembly (). CodeBase) .LocalPath
Mr.Mindor
28
GetExecutingAssemblyretourne l'assembly qui contient le code en cours d'exécution . Il ne s'agit pas nécessairement de l' assembly .exe de la console . Il peut s'agir d'un assemblage qui a été chargé à partir d'un emplacement totalement différent. Vous devrez utiliser GetEntryAssembly! Notez également que cela CodeBasepeut ne pas être défini lorsque l'assembly est dans le GAC. La meilleure alternative est AppDomain.CurrentDomain.BaseDirectory.
bitbonk
3
Veuillez écrire le code dans 4 espaces pour qu'il soit confortable à copier
fnc12
3
si vous appelez dll, System.Reflection.Assembly.GetExecutingAssembly (). CodeBase obtiendra "file: /// C: /Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
raidsan
407

Vous pouvez utiliser le code suivant pour obtenir le répertoire d'application actuel.

AppDomain.CurrentDomain.BaseDirectory
Richard Ev
la source
43
Ne l'utilisez pas. BaseDirectory peut être défini lors de l'exécution. Il n'est pas garanti d'être correct (comme la réponse acceptée est).
usr
3
+1 C'est probablement la réponse que vous souhaitez car elle compense les clichés instantanés.
George Mauer
4
@usr Qu'est-ce qui vous fait penser que cela BaseDirectorypeut être défini lors de l'exécution? Il n'a qu'un getter.
bitbonk
3
@bitbonk, il peut être défini au moment de la création du domaine d'application.
usr
3
N'est-ce pas que BaseDirectory peut être modifié dans un fichier * .lnk, dans le champ "Démarrer dans:"?
Alexander
170

Vous avez deux options pour trouver le répertoire de l'application, que vous choisirez dépendra de votre objectif.

// 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);
Mr.Mindor
la source
3
Je voulais juste dire, évidemment, il y a beaucoup plus de 2 options par combien d'autres choix sont affichés ...
vapcguy
17
Si tout ce que vous essayez de faire avec ledit chemin ne prend pas en charge le format URI, utilisezvar localDirectory = new Uri(directory).LocalPath;
Scott Solmer
C'est tout simplement faux. Qu'est-ce que l'exécutable n'est pas du tout un assemblage .NET? La bonne réponse est de vérifier l'environnement et d'inspecter la ligne de commande.
marquez le
@ Ukuma.Scott Cela ne fonctionne pas si le chemin contient & ou #
MatsW
82

Probablement un peu en retard mais cela vaut la peine d'être mentionné:

Environment.GetCommandLineArgs()[0];

Ou plus correctement pour obtenir uniquement le chemin du répertoire:

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

Éditer:

Beaucoup de gens ont souligné qu'il GetCommandLineArgsn'est pas garanti de retourner le nom du programme. Voir Le premier mot sur la ligne de commande est le nom du programme uniquement par convention . L'article indique que "Bien que très peu de programmes Windows utilisent cette bizarrerie (je n'en connais pas moi-même)". Il est donc possible de «falsifier» GetCommandLineArgs, mais nous parlons d'une application console. Les applications de console sont généralement rapides et sales. Cela correspond donc à ma philosophie KISS.

Steve Mc
la source
1
@ la situation à laquelle vous faites allusion est très théorique. Dans le contexte d'une application console, cela n'a pas vraiment de sens d'utiliser une autre méthode. Rester simple!
Steve Mc
1
@usr mmm - regarder la colonne taskmgr cmdline sauvegarde ce que je dis. Quelques services système avec juste le nom exe. Ça ne fait rien. Ce que j'essaie de dire, c'est que lors du développement d'une application console, il n'est pas nécessaire de rendre les choses plus compliquées qu'elles ne devraient l'être. Surtout quand nous avons déjà les informations disponibles. Maintenant, si vous exécutez une application console de manière à tromper GetCommandLineArgs, vous sautez déjà dans des cerceaux et vous devrez probablement vous demander si une application console est la bonne solution.
Steve Mc
5
Votre solution "simple" implique deux appels de méthode. La solution "compliquée" implique deux appels de méthode. Aucune différence pratique - sauf que la solution "simple" peut vous donner la mauvaise réponse dans certaines circonstances qui ne sont pas sous votre contrôle lorsque vous écrivez le programme. Pourquoi prendre le risque? Utilisez les deux autres appels de méthode et votre programme ne sera pas plus compliqué mais plus fiable.
Chris
3
A fonctionné pour mon scénario, les autres solutions ne l'ont pas fait, donc merci d'avoir fourni une autre alternative :-) J'utilisais le lanceur de test ReSharper pour exécuter un test MS Unit et le code que je testais avait besoin d'un .dll spécifique pour être dans le répertoire d'exécution. ..et Assembly.GetExecutingDirectory () renvoie étrangement un résultat différent.
wallismark
1
@Chris - à la défense de cette réponse. Cela fonctionne pour les tests unitaires, contrairement à la solution GetEntryAssembly, car GetEntryAssembly renvoie null. Les réponses qui proposent GetExecutingAssembly sont fausses, car elles ne renvoient l'exécutable que si l'assembly en cours d'exécution est l'exécutable. Ce n'est pas la solution simple, mais la bonne.
marquez le
44

Pour toute personne intéressée par les applications Web asp.net. Voici mes résultats de 3 méthodes différentes

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

résultat

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'application s'exécute physiquement à partir de "C: \ inetpub \ SBSPortal_staging", donc la première solution n'est certainement pas appropriée pour les applications Web.

fusées rapides
la source
42

La réponse ci-dessus était de 90% de ce dont j'avais besoin, mais a renvoyé un Uri au lieu d'un chemin normal pour moi.

Comme expliqué dans le message des forums MSDN, comment convertir le chemin URI en chemin de fichier normal? , J'ai utilisé ce qui suit:

// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;
pétillé
la source
1
cela fonctionne bien également si l'exe en question est un service Windows et que le répertoire actuel renvoie C: \ Windows \ system32. Le code ci-dessus renvoie l'emplacement réel de l'exe
DaImTo
Sauf si vous essayez ensuite de faire quelque chose comme File.CreateDirectory(path)ça, cela vous donnera l'exception qu'il n'autorise pas les chemins URI ...
vapcguy
1
Malheureusement, cela ne fonctionne pas pour les chemins qui contiennent un identifiant de fragment (le #caractère). L'identifiant et tout ce qui le suit est tronqué du chemin résultant.
bgfvdu3w
Pourquoi ne changez-vous pas new Uriet System.IO.Path.GetDirectoryName? Cela vous donne une chaîne de chemin normale au lieu d'un Uri.
Timo
Je trouve que c'est le meilleur. Cette même approche a fonctionné de manière fiable pour moi dans n'importe quel environnement. En production, débogage local, tests unitaires ... Vous voulez ouvrir un fichier de contenu que vous avez inclus ("contenu - copier si plus récent") dans un test unitaire? C'est là.
Timo
29

Vous cherchez peut-être à faire ceci:

System.IO.Path.GetDirectoryName(
    System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase)
ist_lion
la source
23

vous pouvez utiliser celui-ci à la place.

System.Environment.CurrentDirectory
ButtShock
la source
Cela obtiendra le dossier de l'exécutable
Iain
Cela peut être modifié de plusieurs façons (paramètres de raccourci, etc.) ... mieux vaut NE PAS l'utiliser.
Yousha Aleayoub
23

Si vous recherchez un moyen compatible avec .NET Core, utilisez

System.AppContext.BaseDirectory

Cela a été introduit dans .NET Framework 4.6 et .NET Core 1.0 (et .NET Standard 1.3). Voir: AppContext.BaseDirectory, propriété .

Selon cette page ,

Il s'agit du remplacement préféré d'AppDomain.CurrentDomain.BaseDirectory dans .NET Core

Dejan
la source
1
voir aussi github.com/dotnet/runtime/issues/13051 pour les applications de console dotnet autonomes. La recommandation ici est d'utiliserProcess.GetCurrentProcess().MainModule.FileName
Gavin
19

Pour les applications console, vous pouvez essayer ceci:

System.IO.Directory.GetCurrentDirectory();

Sortie (sur ma machine locale):

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

Ou vous pouvez essayer (il y a une barre oblique inverse supplémentaire à la fin):

AppDomain.CurrentDomain.BaseDirectory

Production:

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

F.Alves
la source
"Le BaseDirectorypeut être réglé au moment de l'exécution. Il n'est PAS garanti d'être correct"
Yousha Aleayoub
14

J'ai utilisé ce code et j'ai trouvé la solution.

AppDomain.CurrentDomain.BaseDirectory
Solution logicielle Trimantra
la source
9

Vous pouvez simplement ajouter à vos références de projet System.Windows.Forms, puis utiliser le System.Windows.Forms.Application.StartupPath comme d'habitude.

Donc, pas besoin de méthodes plus compliquées ou d'utiliser la réflexion.

fruggiero
la source
J'ai utilisé celui-là, et cela fonctionne bien. Mais une fois, j'ai utilisé la méthode dans mon projet de test unitaire. Et bien sûr, il a échoué car il recherchait mon fichier dans C: \ PROGRAM FILES (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW
ainasiart
@ainasiart alors comment puis-je faire fonctionner cela pendant les tests unitaires ??
Nicholas Siegmundt
8

La ligne suivante vous donnera un chemin d'application:

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

La solution ci-dessus fonctionne correctement dans les situations suivantes:

  • application simple
  • dans un autre domaine où Assembly.GetEntryAssembly () retournerait null
  • La DLL est chargée à partir des ressources incorporées en tant que tableau d'octets et chargée dans AppDomain en tant que Assembly.Load (byteArrayOfEmbeddedDll)
  • avec les mkbundlebundles de Mono (aucune autre méthode ne fonctionne)
user2126375
la source
Sous le débogueur sous Linux, cela renvoie: / usr / share / dotnet
Vladimir
7

J'utilise ceci si l'exe est censé être appelé en double-cliquant dessus

var thisPath = System.IO.Directory.GetCurrentDirectory();
developer747
la source
5
Ce n'est pas correct car vous pouvez obtenir des répertoires aléatoires en résultat.
Amuliar
cette commande renvoie Environment.CurrentDirectory, qui peut être modifié au moment de l'exécution sur n'importe quel chemin, il ne s'agit donc pas d'une solution fiable.
Yury Kozlov
7

j'ai utilisé

System.AppDomain.CurrentDomain.BaseDirectory

quand je veux trouver un chemin par rapport à un dossier d'applications. Cela fonctionne pour les applications ASP.Net et Winform. Il ne nécessite également aucune référence aux assemblys System.Web.

user2346593
la source
6

Je veux dire, pourquoi ne pas utiliser la méthode 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());
                }
            }
    }

Vous l'utiliseriez comme Application.StartupPath:

    Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");
user3596865
la source
2
Pourquoi p / invoquer alors qu'il y a autant de .NET pour cela?
ProfK
7
@ user3596865 car il requiert une forte dépendance à Windows et n'est pas compatible avec DNX ou Mono. Et il y a peut-être un changement de rupture dans les futures versions de Windows. Encore une fois: pourquoi devrions-nous utiliser le pinvoke ici?
Ben
5

Assembly.GetEntryAssembly().Location ou Assembly.GetExecutingAssembly().Location

À utiliser en combinaison avec System.IO.Path.GetDirectoryName()pour obtenir uniquement le répertoire.

Les chemins depuis GetEntryAssembly()et GetExecutingAssembly()peuvent être différents, même si dans la plupart des cas le répertoire sera le même.

Avec GetEntryAssembly()vous devez être conscient que cela peut retourner nullsi le module d'entrée n'est pas géré (c'est-à-dire exécutable C ++ ou VB6). Dans ces cas, il est possible d'utiliser à GetModuleFileNamepartir de l'API Win32:

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

dans VB.net

My.Application.Info.DirectoryPath

fonctionne pour moi (Type d'application: Bibliothèque de classes). Pas sûr de C # ... Renvoie le chemin sans nom de fichier sous forme de chaîne

dba
la source
4
AppDomain.CurrentDomain.BaseDirectory

Résoudra le problème pour référencer les fichiers de référence tiers avec les packages d'installation.

Nirav Mehta
la source
11
Cette réponse a déjà été suggérée il y a 5 ans, voire plus d'une fois.
PL
2

Aucune de ces méthodes ne fonctionne dans des cas particuliers comme l'utilisation d'un lien symbolique vers l'exe, elles renverront l'emplacement du lien et non l'exe réel.

Vous pouvez donc utiliser QueryFullProcessImageName pour contourner cela:

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) + @"\";
    }
}
colin lamarre
la source
2

Essayez cette simple ligne de code:

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

Une autre solution consiste à utiliser des chemins relatifs pointant vers le chemin actuel:

Path.GetFullPath(".")
blenderfreaky
la source
Cela obtient le répertoire actuel, pas l'emplacement de l'EXE de départ.
tenfour
0

Je n'ai vu personne convertir le LocalPath fourni par la réflexion .Net Core en un chemin System.IO utilisable alors voici ma version.

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

   return new FileInfo(exePath).DirectoryName;

}

Cela renverra le chemin d'accès complet au format "C: \ xxx \ xxx" à l'emplacement de votre code.

marque gamache
la source
-1

Voici une solution fiable qui fonctionne avec des applications 32 bits et 64 bits .

Ajoutez ces références:

en utilisant System.Diagnostics;

en utilisant System.Management;

Ajoutez cette méthode à votre projet:

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

Maintenant, utilisez-le comme ceci:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Notez que si vous connaissez l'id du processus, cette méthode renverra le chemin ExecutePath correspondant.

Extra, pour ceux qui sont intéressés:

Process.GetProcesses() 

... vous donnera un tableau de tous les processus en cours d'exécution, et ...

Process.GetCurrentProcess()

... vous donnera le processus en cours, ainsi que leurs informations, par exemple Id, etc. et également un contrôle limité, par exemple Kill, etc. *

WonderWorker
la source
-5

Vous pouvez créer un nom de dossier en tant que ressources dans le projet à l'aide de l'Explorateur de solutions, puis vous pouvez coller un fichier dans les ressources.

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);
}
Devarajan.T
la source
6
Utiliser Environment.CurrentDirectory est très faux, ne l'utilisez pas! ce chemin peut changer au moment de l'exécution. Même au démarrage, il n'est pas déterministe.
usr