Wie kann ich den Pfad der Anwendung in einer .NET-Konsolenanwendung abrufen?

953

Wie finde ich den Pfad der Anwendung in einer Konsolenanwendung?

In Windows Forms kann ich Application.StartupPathden aktuellen Pfad suchen, dies scheint jedoch in einer Konsolenanwendung nicht verfügbar zu sein.

JSmyth
quelle
5
Installieren Sie .NET Framework auf dem Zielcomputer (Client, Entwicklung)? wenn deine Antwort wahr ist; Sie können also einen Verweis auf System.Windows.Forms.dll hinzufügen und Application.StartupPath verwenden! Dies ist der beste Weg, wenn Sie weitere zukünftige Ausnahmen entfernen möchten!
Ehsan Mohammadi
AppDomain.BaseDirectory ist das App-Verzeichnis. Beachten Sie, dass sich Anwendungen in VS env und Win env unterschiedlich verhalten können. Aber AppDomain sollte nicht mit application.path identisch sein, aber ich hoffe, dass dies nicht nur für IIS gilt.
Mertuarez

Antworten:

1179

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

Kombinieren Sie das mit, System.IO.Path.GetDirectoryNamewenn Sie nur das Verzeichnis wollen.

1 Gemäß dem Kommentar von Mr.Mindor: Gibt
System.Reflection.Assembly.GetExecutingAssembly().Location zurück, wo sich die ausführende Assembly befindet, die sich möglicherweise dort befindet, wo sich die Assembly befindet, wenn sie nicht ausgeführt wird. Im Fall von Schattenkopier-Assemblys erhalten Sie einen Pfad in einem temporären Verzeichnis. System.Reflection.Assembly.GetExecutingAssembly().CodeBasegibt den 'permanenten' Pfad der Assembly zurück.

Sam Axe
quelle
243
System.Reflection.Assembly.GetExecutingAssembly (). Standort zurückkehrt , wo die vollsAnordnung zur Zeit befindet, die sein kann oder nicht , wo die Anordnung angeordnet ist , wenn sie nicht ausgeführt wird . Im Fall von Schattenkopier-Assemblys erhalten Sie einen Pfad in einem temporären Verzeichnis. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase gibt den ' dauerhaften ' Pfad der Assembly zurück.
Mr. Mindor
13
@SamGoldberg: Das hängt davon ab, wie es verwendet wird: stackoverflow.com/q/1068420/391656 . Oder Sie können ... neue Uri (System.Reflection.Assembly.GetExecutingAssembly (). CodeBase) .LocalPath
Mr.Mindor
28
GetExecutingAssemblyGibt eine Assembly zurück, die den aktuell ausgeführten Code enthält . Dies muss nicht unbedingt die .exe- Assembly der Konsole sein . Es kann sich um eine Baugruppe handeln, die von einem völlig anderen Ort geladen wurde. Sie müssen verwenden GetEntryAssembly! Beachten Sie auch, dass dies CodeBasemöglicherweise nicht festgelegt wird, wenn sich die Baugruppe im GAC befindet. Die bessere Alternative ist AppDomain.CurrentDomain.BaseDirectory.
Bitbonk
3
Bitte schreiben Sie Code in 4 Leerzeichen, damit es bequem zu kopieren ist
fnc12
3
Wenn Sie dll aufrufen, erhält System.Reflection.Assembly.GetExecutingAssembly (). CodeBase erhält "file: /// C: /Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"
raidsan
407

Mit dem folgenden Code können Sie das aktuelle Anwendungsverzeichnis abrufen.

AppDomain.CurrentDomain.BaseDirectory
Richard Ev
quelle
43
Benutze das nicht. Das BaseDirectory kann zur Laufzeit festgelegt werden. Es ist nicht garantiert, dass es korrekt ist (wie die akzeptierte Antwort lautet).
usr
3
+1 Dies ist wahrscheinlich die gewünschte Antwort, da sie das Kopieren von Schatten kompensiert.
George Mauer
4
@usr Was lässt Sie denken, dass BaseDirectorydies zur Laufzeit eingestellt werden kann? Es hat nur einen Getter.
Bitbonk
3
@bitbonk kann zum Zeitpunkt der Appdomain-Erstellung festgelegt werden.
usr
3
Kann BaseDirectory nicht in einer * .lnk-Datei im Feld "Start in:" geändert werden?
Alexander
170

Sie haben zwei Möglichkeiten, um das Verzeichnis der Anwendung zu finden, das Sie je nach Verwendungszweck auswählen.

// 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
quelle
3
Ich wollte nur sagen, offensichtlich gibt es viel mehr als 2 Optionen, je
nachdem,
17
Wenn das, was Sie mit diesem Pfad versuchen, das URI-Format nicht unterstützt, verwenden Sievar localDirectory = new Uri(directory).LocalPath;
Scott Solmer
Das ist einfach falsch. Was ist die ausführbare Datei ist überhaupt keine .NET-Assembly? Die richtige Antwort besteht darin, die Umgebung zu überprüfen und die Befehlszeile zu überprüfen.
Markieren Sie den
@ Ukuma.Scott Dies funktioniert nicht, wenn der Pfad & oder #
MatsW
82

Wahrscheinlich etwas spät, aber das ist eine Erwähnung wert:

Environment.GetCommandLineArgs()[0];

Oder genauer gesagt, um nur den Verzeichnispfad zu erhalten:

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

Bearbeiten:

Nicht wenige Leute haben darauf hingewiesen, dass GetCommandLineArgsdie Rückgabe des Programmnamens nicht garantiert ist. Siehe Das erste Wort in der Befehlszeile ist der Programmname nur gemäß Konvention . In dem Artikel heißt es: "Obwohl extrem wenige Windows-Programme diese Eigenart verwenden (mir sind keine bekannt)." Es ist also möglich, zu "fälschen" GetCommandLineArgs, aber es handelt sich um eine Konsolenanwendung. Konsolen-Apps sind normalerweise schnell und schmutzig. Das passt also zu meiner KISS-Philosophie.

Steve Mc
quelle
1
@usr die Situation, auf die Sie anspielen, ist sehr theoretisch. Im Kontext einer Konsolenanwendung ist es nicht wirklich sinnvoll, eine andere Methode zu verwenden. Halte es einfach!
Steve Mc
1
@usr mmm - Ein Blick auf die Spalte taskmgr cmdline bestätigt, was ich sage. Einige Systemdienste mit nur dem Namen exe. Keine Ursache. Ich versuche zu sagen, dass es bei der Entwicklung einer Konsolenanwendung nicht erforderlich ist, die Dinge komplizierter zu gestalten, als sie sein müssen. Vor allem, wenn wir die Informationen bereits zur Verfügung haben. Wenn Sie jetzt eine Konsolenanwendung so ausführen, dass GetCommandLineArgs ausgetrickst wird, springen Sie bereits durch die Rahmen und müssen sich wahrscheinlich fragen, ob eine Konsolenanwendung der richtige Weg ist.
Steve Mc
5
Ihre "einfache" Lösung umfasst zwei Methodenaufrufe. Die "komplizierte" Lösung beinhaltet zwei Methodenaufrufe. Kein praktischer Unterschied - außer dass die "einfache" Lösung unter bestimmten Umständen die falsche Antwort geben kann, die Sie beim Schreiben des Programms nicht kontrollieren können. Warum das Risiko eingehen? Verwenden Sie die beiden anderen Methodenaufrufe, und Ihr Programm wird nicht komplizierter, sondern zuverlässiger.
Chris
3
Für mein Szenario funktionierten die anderen Lösungen nicht. Vielen Dank, dass Sie eine andere Alternative bereitgestellt haben :-) Ich habe ReSharper Test Runner verwendet, um einen MS Unit-Test auszuführen, und für den Code, den ich getestet habe, war eine bestimmte DLL erforderlich, um sich im ausführenden Verzeichnis zu befinden. ..und Assembly.GetExecutingDirectory () gibt seltsamerweise ein anderes Ergebnis zurück.
Wallismark
1
@ Chris - zur Verteidigung dieser Antwort. Es funktioniert für Komponententests, die GetEntryAssembly-Lösung nicht, da GetEntryAssembly null zurückgibt. Die Antworten, die GetExecutingAssembly vorschlagen, sind falsch, da sie die ausführbare Datei nur zurückgeben, wenn die ausführende Assembly die ausführbare Datei ist. Dies ist nicht die einfache, sondern die richtige Lösung.
Markieren Sie den
44

Für alle, die sich für asp.net Web Apps interessieren. Hier sind meine Ergebnisse von 3 verschiedenen Methoden

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

Ergebnis

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

Die App wird physisch von "C: \ inetpub \ SBSPortal_staging" ausgeführt, sodass die erste Lösung definitiv nicht für Web-Apps geeignet ist.

Raketen sind schnell
quelle
42

Die Antwort oben war 90% von dem, was ich brauchte, gab aber einen Uri anstelle eines regulären Pfades für mich zurück.

Wie im Beitrag in den MSDN-Foren erläutert , konvertieren Sie den URI-Pfad in einen normalen Dateipfad. Ich habe folgendes verwendet:

// Get normal filepath of this assembly's permanent directory
var path = new Uri(
    System.IO.Path.GetDirectoryName(
        System.Reflection.Assembly.GetExecutingAssembly().CodeBase)
    ).LocalPath;
zischte
quelle
1
Dies funktioniert auch dann gut, wenn es sich bei der fraglichen Exe um einen Windows-Dienst handelt und das aktuelle Verzeichnis C: \ Windows \ system32 zurückgibt. Der obige Code gibt den tatsächlichen Speicherort der exe zurück
DaImTo
Außer wenn Sie dann versuchen, so etwas zu tun File.CreateDirectory(path), gibt es Ihnen die Ausnahme, dass es keine URI-Pfade erlaubt ...
vapcguy
1
Leider funktioniert dies nicht für Pfade, die eine Fragmentkennung (das #Zeichen) enthalten. Der Bezeichner und alles, was darauf folgt, wird vom resultierenden Pfad abgeschnitten.
bgfvdu3w
Warum tauschst du nicht new Uriund System.IO.Path.GetDirectoryName? Das gibt Ihnen eine normale Pfadzeichenfolge anstelle von a Uri.
Timo
Ich finde das am besten. Der gleiche Ansatz hat für mich in jeder Umgebung zuverlässig funktioniert. In der Produktion, lokales Debuggen, Komponententests ... Möchten Sie eine Inhaltsdatei öffnen, die Sie in einen Komponententest aufgenommen haben ("Inhalt - Kopie, wenn neuer")? Es ist da.
Timo
29

Möglicherweise möchten Sie dies tun:

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

Sie können stattdessen diesen verwenden.

System.Environment.CurrentDirectory
ButtShock
quelle
Dies wird jedoch den Ordner der ausführbaren Datei erhalten
Iain
Dies kann auf verschiedene Arten geändert werden (Verknüpfungseinstellungen usw.) ... besser NICHT verwenden.
Yousha Aleayoub
23

Wenn Sie nach einer .NET Core-kompatiblen Methode suchen, verwenden Sie

System.AppContext.BaseDirectory

Dies wurde in .NET Framework 4.6 und .NET Core 1.0 (und .NET Standard 1.3) eingeführt. Siehe: AppContext.BaseDirectory-Eigenschaft .

Laut dieser Seite ,

Dies ist der bevorzugte Ersatz für AppDomain.CurrentDomain.BaseDirectory in .NET Core

Dejan
quelle
1
Siehe auch github.com/dotnet/runtime/issues/13051 für eigenständige Dotnet-Konsolen-Apps. Die Empfehlung hier ist zu verwendenProcess.GetCurrentProcess().MainModule.FileName
Gavin
19

Für Konsolenanwendungen können Sie Folgendes versuchen:

System.IO.Directory.GetCurrentDirectory();

Ausgabe (auf meinem lokalen Computer):

c: \ Benutzer \ xxxxxxx \ Dokumente \ Visual Studio 2012 \ Projekte \ ImageHandler \ GetDir \ bin \ Debug

Oder Sie können es versuchen (am Ende gibt es einen zusätzlichen Backslash):

AppDomain.CurrentDomain.BaseDirectory

Ausgabe:

c: \ Benutzer \ xxxxxxx \ Dokumente \ Visual Studio 2012 \ Projekte \ ImageHandler \ GetDir \ bin \ Debug \

F. Alves
quelle
"Das BaseDirectorykann zur Laufzeit eingestellt werden. Es ist NICHT garantiert, dass es korrekt ist"
Yousha Aleayoub
14

Ich habe diesen Code verwendet und die Lösung erhalten.

AppDomain.CurrentDomain.BaseDirectory
Trimantra-Softwarelösung
quelle
9

Sie können einfach zu Ihren Projektreferenzen hinzufügen System.Windows.Formsund diese dann System.Windows.Forms.Application.StartupPath wie gewohnt verwenden.

Sie brauchen also keine komplizierteren Methoden oder die Verwendung der Reflexion.

fruggiero
quelle
Ich habe das benutzt und es funktioniert gut. Aber einmal habe ich die Methode in meinem Unit-Test-Projekt verwendet. Und natürlich ist es fehlgeschlagen, weil es nach meiner Datei in C: \ PROGRAMMDATEIEN (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW gesucht hat
ainasiart
@ainasiart Also, wie kann ich das beim Unit-Test zum Laufen bringen?
Nicholas Siegmundt
8

In der folgenden Zeile erhalten Sie einen Anwendungspfad:

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

Die obige Lösung funktioniert in den folgenden Situationen ordnungsgemäß:

  • einfache App
  • in einer anderen Domäne, in der Assembly.GetEntryAssembly () null zurückgeben würde
  • DLL wird aus eingebetteten Ressourcen als Byte-Array geladen und als Assembly.Load (byteArrayOfEmbeddedDll) in AppDomain geladen.
  • mit Monos mkbundleBundles (keine anderen Methoden funktionieren)
user2126375
quelle
Unter Debugger unter Linux wird Folgendes zurückgegeben: / usr / share / dotnet
Vladimir
7

Ich benutze dies, wenn die Exe durch Doppelklick aufgerufen werden soll

var thisPath = System.IO.Directory.GetCurrentDirectory();
Entwickler747
quelle
5
Dies ist nicht korrekt, da Sie im Ergebnis zufällige Verzeichnisse erhalten können.
eigenartig
Dieser Befehl gibt Environment.CurrentDirectory zurück, das zur Laufzeit in einen beliebigen Pfad geändert werden kann. Daher ist es keine zuverlässige Lösung.
Yury Kozlov
7

Ich habe benutzt

System.AppDomain.CurrentDomain.BaseDirectory

wenn ich einen Pfad relativ zu einem Anwendungsordner finden möchte. Dies funktioniert sowohl für ASP.Net- als auch für Winform-Anwendungen. Es ist auch kein Verweis auf System.Web-Assemblys erforderlich.

user2346593
quelle
6

Ich meine, warum nicht ap / invoke Methode?

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

Sie würden es genau wie Application.StartupPath verwenden:

    Console.WriteLine("The path to this executable is: " + AppInfo.StartupPath + "\\" + System.Diagnostics.Process.GetCurrentProcess().ProcessName + ".exe");
user3596865
quelle
2
Warum p / invoke, wenn es dafür so viel .NET gibt?
ProfK
7
@ user3596865, da dies eine starke Abhängigkeit von Windows erfordert und nicht mit DNX oder Mono kompatibel ist. Und vielleicht gibt es eine bahnbrechende Änderung in zukünftigen Windows-Versionen. Also nochmal: Warum sollten wir hier Pinvoke verwenden?
Ben
5

Assembly.GetEntryAssembly().Location oder Assembly.GetExecutingAssembly().Location

In Kombination mit verwenden System.IO.Path.GetDirectoryName(), um nur das Verzeichnis abzurufen.

Die Pfade von GetEntryAssembly()und GetExecutingAssembly()können unterschiedlich sein, obwohl das Verzeichnis in den meisten Fällen dasselbe ist.

Mit GetEntryAssembly()Ihnen bewusst sein, dass diese zurückgeben kann , nullwenn das Eingabemodul unmanaged ist (dh C ++ oder VB6 ausführbar). In diesen Fällen ist es möglich, GetModuleFileNameüber die Win32-API Folgendes zu verwenden:

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

in VB.net

My.Application.Info.DirectoryPath

funktioniert bei mir (Anwendungstyp: Klassenbibliothek). Nicht sicher über C # ... Gibt den Pfad ohne Dateinamen als Zeichenfolge zurück

dba
quelle
4
AppDomain.CurrentDomain.BaseDirectory

Behebt das Problem, indem auf Referenzdateien von Drittanbietern mit Installationspaketen verwiesen wird.

Nirav Mehta
quelle
11
Diese Antwort wurde bereits vor 5 Jahren vorgeschlagen, sogar mehr als einmal.
PL
2

Keine dieser Methoden funktioniert in besonderen Fällen wie der Verwendung eines symbolischen Links zur Exe. Sie geben den Speicherort des Links zurück, nicht die tatsächliche Exe.

Sie können also QueryFullProcessImageName verwenden , um dies zu umgehen :

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
quelle
2

Versuchen Sie diese einfache Codezeile:

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

Eine andere Lösung besteht darin, relative Pfade zu verwenden, die auf den aktuellen Pfad zeigen:

Path.GetFullPath(".")
Blenderfreaky
quelle
Dadurch wird das aktuelle Verzeichnis abgerufen, nicht der Speicherort der Start-EXE.
10.
0

Ich habe niemanden gesehen, der den von .Net Core Reflection bereitgestellten LocalPath in einen verwendbaren System.IO-Pfad konvertiert hat. Hier ist meine Version.

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

   return new FileInfo(exePath).DirectoryName;

}

Dadurch wird der vollständig mit "C: \ xxx \ xxx" formatierte Pfad zu Ihrem Code zurückgegeben.

Gamache markieren
quelle
-1

Hier ist eine zuverlässige Lösung, die mit 32bit und 64bit funktioniert Anwendungen .

Fügen Sie diese Referenzen hinzu:

using System.Diagnostics;

using System.Management;

Fügen Sie diese Methode Ihrem Projekt hinzu:

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

Verwenden Sie es jetzt so:

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

Beachten Sie, dass diese Methode den entsprechenden ExecutePath zurückgibt, wenn Sie die ID des Prozesses kennen.

Extra für Interessierte:

Process.GetProcesses() 

... gibt Ihnen eine Reihe aller aktuell ausgeführten Prozesse und ...

Process.GetCurrentProcess()

... gibt Ihnen den aktuellen Prozess zusammen mit ihren Informationen, z. B. ID usw. und auch eingeschränkter Kontrolle, z. B. Töten usw. *

WonderWorker
quelle
-5

Sie können mit dem Projektmappen-Explorer einen Ordnernamen als Ressourcen im Projekt erstellen und anschließend eine Datei in die Ressourcen einfügen.

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
quelle
6
Die Verwendung von Environment.CurrentDirectory ist sehr falsch. Verwenden Sie dies nicht! Dieser Pfad kann sich zur Laufzeit ändern. Auch beim Start ist es nicht deterministisch.
usr