.NETコンソールアプリケーションでアプリケーションのパスを取得するにはどうすればよいですか?


953

コンソールアプリケーションでアプリケーションのパスを見つけるにはどうすればよいですか?

Windowsフォーム、私は使用することができApplication.StartupPath、電流経路を見つけることが、これはコンソールアプリケーションで利用可能ではないようです。


5
ターゲット(クライアント、開発)マシンに.NET Frameworkをインストールしますか?あなたの答えが真実なら; したがって、System.Windows.Forms.dllへの参照を追加して、Application.StartupPath!を使用できます。今後の例外をさらに避けたい場合は、これが最善の方法です。
Ehsan Mohammadi

AppDomain.BaseDirectoryはアプリディレクトリです。アプリケーションはVS envとWin envでは動作が異なる場合があることに注意してください。しかし、AppDomainはapplication.pathと同じではないはずですが、これがIISだけではないことを願っています。
Mertuarez

回答:


1179

System.Reflection.Assembly.GetExecutingAssembly()1Location

System.IO.Path.GetDirectoryName必要なのがディレクトリだけの場合は、それを組み合わせます。

1 Mindor氏のコメントに従って:
System.Reflection.Assembly.GetExecutingAssembly().Location実行中のアセンブリが現在配置されている場所を返します。これは、実行されていないときにアセンブリが配置されている場所である場合とそうでない場合があります。シャドウコピーアセンブリの場合、一時ディレクトリにパスを取得します。System.Reflection.Assembly.GetExecutingAssembly().CodeBaseアセンブリの「永続的な」パスを返します。


243
System.Reflection.Assembly.GetExecutingAssembly()。Locationは、実行中のアセンブリが現在配置されている場所を返します。これは、実行されていないときにアセンブリが配置されている場所とは異なる場合があります。シャドウコピーアセンブリの場合、一時ディレクトリにパスを取得します。System.Reflection.Assembly.GetExecutingAssembly()。CodeBaseは、アセンブリの「永続的な」パスを返します。
Mr.Mindor、2011年

13
@SamGoldberg:使用方法によって異なります:stackoverflow.com/q/1068420/391656。または、次のことができます... new Uri(System.Reflection.Assembly.GetExecutingAssembly()。CodeBase).LocalPath
Mr.Mindor

28
GetExecutingAssembly現在実行中のコード含むアセンブリを返します。これは、必ずしもコンソールの.exeアセンブリであるとは限りません。まったく異なる場所からロードされたアセンブリである可能性があります。あなたが使用する必要がありますGetEntryAssembly!またCodeBase、アセンブリがGACにある場合は設定されない場合があることに注意してください。より良い代替案はAppDomain.CurrentDomain.BaseDirectoryです。
bitbonk

3
コピーしやすいように、4つのスペースにコードを記述してください
fnc12

3
dllを呼び出すと、System.Reflection.Assembly.GetExecutingAssembly()。CodeBaseは "file:/// C:/Windows/Microsoft.NET/Framework64/v4.0.30319/mscorlib.dll"を取得します
raidsan

407

次のコードを使用して、現在のアプリケーションディレクトリを取得できます。

AppDomain.CurrentDomain.BaseDirectory

43
これは使わないでください。BaseDirectoryは実行時に設定できます。正しいとは限りません(受け入れられた回答と同様)。
usr

3
+1シャドウコピーを補うため、これはおそらくあなたの答えです。
George Mauer

4
@usr BaseDirectory実行時に設定できると思いますか?ゲッターしかありません。
bitbonk 2015

3
@bitbonkアプリドメインの作成時に設定できます。
usr

3
BaseDirectoryは、*。lnkファイルの "Start in:"フィールドで変更できるのではないですか。
Alexander

170

アプリケーションのディレクトリを見つけるには、目的に応じて2つのオプションがあります。

// 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
言いたかっただけですが、他にいくつの選択肢が投稿されているかによって、明らかに2つ以上の選択肢があります...
vapcguy

17
上記のパスで実行しようとしているものがURI形式をサポートしていない場合は、var localDirectory = new Uri(directory).LocalPath;
Scott Solmer

これは間違っています。実行可能ファイルは.NETアセンブリではありませんか?正しい答えは、環境をチェックしてコマンドラインを調べることです。
マーク

@ Ukuma.Scottパスが&または#を含む場合は機能しません
MatsW

82

おそらく少し遅れますが、これは言及する価値があります:

Environment.GetCommandLineArgs()[0];

または、ディレクトリパスのみを取得するためのより正確な例:

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

編集:

かなりの数の人がGetCommandLineArgsプログラム名を返すことが保証されていないことを指摘しました。コマンドラインの最初の単語は、慣例によるプログラム名のみを参照してください。この記事には、「この癖を使うWindowsプログラムはごくわずかですが(私は自分自身については知りません)」と述べています。したがって、「なりすまし」が可能ですが、ここではGetCommandLineArgsコンソールアプリケーションについて説明します。通常、コンソールアプリは高速でダーティです。これは私のKISSの哲学と一致します。


1
@usrの状況は非常に理論的です。コンソールアプリケーションのコンテキストでは、他の方法を使用しても意味がありません。複雑にしないでおく!
Steve Mc

1
@usr mmm-taskmgr cmdlineカラムを見ると、私が言っていることがバックアップされています。exe名のみのいくつかのシステムサービス。気にしないで。私が言おうとしていることは、コンソールアプリケーションを開発するときに、物事を必要以上に複雑にする必要がないということです。特に、すでに利用可能な情報がある場合。ここで、GetCommandLineArgsをだますような方法でコンソールアプリケーションを実行している場合は、すでにフープを飛び越えているため、おそらくコンソールアプリが適切な方法であるかどうかを自問する必要があります。
スティーブMc

5
「単純な」ソリューションには、2つのメソッド呼び出しが含まれます。「複雑な」ソリューションには、2つのメソッド呼び出しが含まれます。実際の違いはありません。ただし、「単純な」ソリューションでは、プログラムを記述しているときに自分の制御下にない特定の状況で間違った答えが返される場合があります。なぜリスクを取るのか?他の2つのメソッド呼び出しを使用すると、プログラムは複雑ではなくなりますが、信頼性が高くなります。
Chris

3
私のシナリオでは機能しましたが、他のソリューションでは機能しませんでした。別の代替手段を提供してくれてありがとう:-) ReSharperテストランナーを使用してMSユニットテストを実行していて、テストしているコードには、実行ディレクトリに特定の.dllが必要です。 ..and Assembly.GetExecutingDirectory()が奇妙に異なる結果を返します。
wallismark 2015年

1
@Chris-この答えを守るために。GetEntryAssemblyはnullを返すため、単体テストでは機能しますが、GetEntryAssemblyソリューションでは機能しません。GetExecutingAssemblyを提案する回答は、実行中のアセンブリが実行可能ファイルである場合にのみ実行可能ファイルを返すため、偽です。これは簡単ではありませんが、正しい解決策です。
マーク

44

asp.net Webアプリに興味のある人向け。ここに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」から物理的に実行されているため、最初のソリューションはWebアプリには明らかに適切ではありません。


42

上記の答えは必要なものの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;

1
これは、問題のexeがWindowsサービスであり、現在のディレクトリがC:\ Windows \ system32を返す場合にもうまく機能します。上記のコードは、exeの実際の場所を返します
DaImTo

その後File.CreateDirectory(path)、のようなことをしようとする場合を除き、URIパスを許可しないという例外が発生します...
vapcguy

1
残念ながら、これはフラグメント識別子(#文字)を含むパスでは機能しません。識別子とそれに続くすべてのものは、結果のパスから切り捨てられます。
bgfvdu3w 2018

なぜあなたは交換していないnew UriSystem.IO.Path.GetDirectoryName?これにより、の代わりに通常のパス文字列が得られますUri
Timo

私はこれが最高だと思います。これと同じアプローチは、どのような環境でも確実に機能します。本番環境、ローカルでデバッグ、ユニットテスト...ユニットテストに含めたコンテンツファイル(「コンテンツ-新しい場合はコピー」)を開きたいですか?それはそこにある。
Timo

29

あなたはこれを行うことを探しているかもしれません:

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

23

代わりにこれを使用できます。

System.Environment.CurrentDirectory

ただし、実行可能ファイルのフォルダが取得されます
Iain

これはいくつかの方法で変更できます(ショートカット設定など)...使用しない方がよいでしょう。
Yousha Aleayoub

23

.NET Core互換の方法を探している場合は、

System.AppContext.BaseDirectory

これは、.NET Framework 4.6および.NET Core 1.0(および.NET Standard 1.3)で導入されました。参照:AppContext.BaseDirectoryプロパティ

このページによると、

これは、.NET CoreのAppDomain.CurrentDomain.BaseDirectoryの推奨される代替です。


1
自己完結型のドットネットコンソールアプリについては、github.com / dotnet / runtime / issues / 13051ご覧ください。ここでの推奨は、使用することですProcess.GetCurrentProcess().MainModule.FileName
Gavin

19

コンソールアプリケーションの場合、これを試すことができます。

System.IO.Directory.GetCurrentDirectory();

出力(ローカルマシン上):

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

または、試すことができます(最後に追加のバックスラッシュがあります):

AppDomain.CurrentDomain.BaseDirectory

出力:

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


BaseDirectory実行時に設定できます。正確であるとは
限り


9

プロジェクト参照に追加して 、通常どおりをSystem.Windows.Forms使用できますSystem.Windows.Forms.Application.StartupPath

したがって、より複雑な方法や反射を使用する必要はありません。


私はそれを使いました、そしてそれはうまくいきます。しかし、あるときは、単体テストプロジェクトでこのメソッドを使用しました。そしてもちろん、C:\ PROGRAM FILES(X86)\ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW
ainasiart

@ainasiartでは、単体テスト中にこれをどのように機能させるのですか?
Nicholas Siegmundt

8

次の行は、アプリケーションパスを示します。

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

上記のソリューションは、以下の状況で適切に機能しています。

  • シンプルなアプリ
  • Assembly.GetEntryAssembly()がnullを返す別のドメイン
  • DLLは埋め込みリソースからバイト配列として読み込まれ、Assembly.Load(byteArrayOfEmbeddedDll)としてAppDomainに読み込まれます。
  • Monoのmkbundleバンドルあり(他の方法は機能しません)

Linuxのデバッガーでは、これは/ usr / share / dotnet
Vladimir

7

exeをダブルクリックして呼び出すことになっている場合は、これを使用します

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

5
結果としてランダムなディレクトリを取得できるため、これは正しくありません。
13

このコマンドはEnvironment.CurrentDirectoryを返します。これは実行時に任意のパスに変更される可能性があるため、信頼できるソリューションではありません。
Yury Kozlov

7

利用した

System.AppDomain.CurrentDomain.BaseDirectory

アプリケーションフォルダからの相対パスを検索する場合。これはASP.Netとwinformアプリケーションの両方で機能します。また、System.Webアセンブリへの参照も必要ありません。


6

つまり、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());
                }
            }
    }

Application.StartupPathと同じように使用します。

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

2
これに対して.NETが非常に多いときに、なぜp / invokeするのですか?
ProfK 2015

7
@ user3596865これは、Windowsへの強い依存関係が必要であり、DNXまたはMonoと互換性がないためです。そして、おそらく、将来のWindowsバージョンに重大な変更があるでしょう。繰り返しますが、なぜここでpinvokeを使用する必要があるのですか?
Ben

5

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

5

VB.net

My.Application.Info.DirectoryPath

私のために動作します(アプリケーションタイプ:クラスライブラリ)。C#についてわからない...ファイル名なしのパスを文字列として返す


4
AppDomain.CurrentDomain.BaseDirectory

問題を解決して、インストールパッケージでサードパーティの参照ファイルを参照します。


11
この回答は5年前にすでに提案されており、1回以上です。
PL

2

これらのメソッドはいずれも、exeへのシンボリックリンクを使用するなどの特殊なケースでは機能せず、実際のexeではなくリンクの場所を返します。

したがって、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) + @"\";
    }
}

2

次の簡単なコード行を試してください。

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

1

別の解決策は、現在のパスを指す相対パスを使用することです。

Path.GetFullPath(".")

これは、開始EXEの場所ではなく、現在のディレクトリを取得します。
テンフォア

0

.Net Coreリフレクションによって提供されるLocalPathを使用可能なSystem.IOパスに変換する人を見かけなかったので、これが私のバージョンです。

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

   return new FileInfo(exePath).DirectoryName;

}

これにより、コードの場所への完全な「C:\ xxx \ xxx」形式のパスが返されます。



-1

32ビット64 ビットで動作する信頼できるソリューションは次のとおりですアプリケーションです。

これらの参照を追加します。

System.Diagnosticsを使用します。

System.Managementを使用します。

このメソッドをプロジェクトに追加します。

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

次のように使用します。

int RootProcessId = Process.GetCurrentProcess().Id;

GetProcessPath(RootProcessId);

プロセスのIDがわかっている場合、このメソッドは対応するExecutePathを返すことに注意してください。

興味のある方のために:

Process.GetProcesses() 

...現在実行中のすべてのプロセスの配列が表示されます...

Process.GetCurrentProcess()

...現在のプロセスとそれらの情報(IDなど)や制限された制御(Killなど)を提供します*


-5

ソリューションエクスプローラーを使用して、プロジェクト内にリソースとしてフォルダー名を作成し、リソース内にファイルを貼り付けることができます。

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の使用は非常に間違っています。これを使用しないでください!このパスは実行時に変更される可能性があります。起動時でも非決定的です。
usr
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.