.NET 콘솔 응용 프로그램에서 응용 프로그램의 경로를 얻으려면 어떻게해야합니까?


953

콘솔 응용 프로그램에서 응용 프로그램의 경로를 어떻게 찾습니까?

에서 윈도우 폼 , 내가 사용할 수있는 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 Mr.Mindor의 의견에 따라 :
System.Reflection.Assembly.GetExecutingAssembly().Location 실행중인 조립품이 현재 위치한 곳을 반환합니다. 섀도 복사 어셈블리의 경우 temp 디렉토리에 경로가 있습니다. System.Reflection.Assembly.GetExecutingAssembly().CodeBase어셈블리의 '영구적'경로를 반환합니다.


243
System.Reflection.Assembly.GetExecutingAssembly (). Location은 실행중인 어셈블리가 현재 있는 위치를 반환하며, 실행 하지 않을 때 어셈블리가있는 위치 일 수도 있고 아닐 수도 있습니다. 섀도 복사 어셈블리의 경우 temp 디렉토리에 경로가 있습니다. System.Reflection.Assembly.GetExecutingAssembly (). CodeBase는 어셈블리 의 ' permenant '경로를 반환합니다 .
Mr.Mindor

13
@ SamGoldberg : 사용 방법에 따라 다릅니다 : stackoverflow.com/q/1068420/391656 . 또는 당신은 할 수 ... 새로운 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"을
얻습니다

407

다음 코드를 사용하여 현재 응용 프로그램 디렉토리를 얻을 수 있습니다.

AppDomain.CurrentDomain.BaseDirectory

42
이것을 사용하지 마십시오. BaseDirectory는 런타임에 설정할 수 있습니다. (정답이 맞는 것처럼) 정확하지는 않습니다.
usr

3
+1 섀도 복사를 보완하므로 원하는 답이 될 수 있습니다.
George Mauer

4
@usr BaseDirectory런타임에 설정할 수 있다고 생각하는 것은 무엇입니까 ? 게터 만 있습니다.
bitbonk

3
@bitbonk appdomain 생성 시간에 설정할 수 있습니다.
usr

3
BaseStartory를 ".에서 시작 :"필드의 * .lnk 파일에서 변경할 수 있습니까?
Alexander

170

응용 프로그램의 디렉토리를 찾는 데는 두 가지 옵션이 있습니다. 선택하는 것은 목적에 따라 다릅니다.

// 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
var localDirectory = new Uri(directory).LocalPath;
위에서

이것은 단지 잘못이다. 실행 파일이 .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를 속이는 방식으로 콘솔 응용 프로그램을 실행하는 경우 이미 농구 대를 뛰어 넘고 있으며 콘솔 응용 프로그램이 올바른 방법인지 스스로에게 물어봐야 할 것입니다.
Steve Mc

5
"간단한"솔루션에는 두 가지 메소드 호출이 포함됩니다. "복잡한"솔루션에는 두 가지 메소드 호출이 포함됩니다. 실질적인 차이는 없습니다. "간단한"솔루션은 프로그램 작성시 통제 할 수없는 특정 상황에서 잘못된 답변을 제공 할 수 있다는 점을 제외하고. 왜 위험을 감수합니까? 다른 두 가지 메소드 호출을 사용하면 프로그램은 더 복잡하지 않지만 더 안정적입니다.
Chris

3
내 시나리오에서 일한 다른 솔루션은 그렇지 않았으므로 다른 대안을 제공해 주셔서 감사합니다. :-) ReSharper 테스트 러너를 사용하여 MS Unit 테스트를 실행하고 있었고 테스트하는 코드에 특정 .dll이 실행 디렉토리에 있어야했습니다. .. 및 Assembly.GetExecutingDirectory ()가 이상하게 다른 결과를 반환합니다.
wallismark

1
@Chris-이 답변의 방어에. GetEntryAssembly가 null을 반환하기 때문에 단위 테스트에 적합하지만 GetEntryAssembly 솔루션은 그렇지 않습니다. 실행중인 어셈블리가 실행 파일 인 경우에만 실행 파일을 반환하므로 GetExecutingAssembly를 제안하는 답변은 허위입니다. 이것은 간단하지 않지만 올바른 해결책입니다.
마크

44

asp.net 웹앱에 관심이있는 사람 다음은 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"에서 실행 중이므로 첫 번째 솔루션은 웹 앱에는 적합하지 않습니다.


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

왜 교체하지 않는 new UriSystem.IO.Path.GetDirectoryName? 그러면 a 대신 일반 경로 문자열이 제공됩니다 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를 대체하는 것이 좋습니다.


자체 포함 된 닷넷 콘솔 앱에 대해서는 github.com/dotnet/runtime/issues/13051 도 참조하십시오 . 여기에 추천 사용하는 것입니다Process.GetCurrentProcess().MainModule.FileName
개빈

19

콘솔 응용 프로그램의 경우 다음을 시도 할 수 있습니다.

System.IO.Directory.GetCurrentDirectory();

내 로컬 컴퓨터에서 출력 :

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

또는 시도해 볼 수 있습니다 (결국에 추가 백 슬래시가 있습니다).

AppDomain.CurrentDomain.BaseDirectory

산출:

c : \ 사용자 \ xxxxxxx \ documents \ visual studio 2012 \ 프로젝트 \ ImageHandler \ GetDir \ bin \ Debug \


" BaseDirectory런타임에서 설정할 수 있습니다. 정확하지는 않습니다"
Yousha Aleayoub


9

프로젝트 참조에 추가 System.Windows.Forms한 다음 System.Windows.Forms.Application.StartupPath 평소 와 같이 사용할 수 있습니다 .

따라서 더 복잡한 방법이나 반사를 사용할 필요가 없습니다.


나는 그 것을 사용했고 잘 작동합니다. 그러나 한 번은 단위 테스트 프로젝트에서 메소드를 사용했습니다. \ PROGRAM FILES (X86) \ MICROSOFT VISUAL STUDIO 14.0 \ COMMON7 \ IDE \ COMMONEXTENSIONS \ MICROSOFT \ TESTWINDOW : 그것은 C에서 내 파일을 찾고 있었기 때문에 물론, 그것은 실패
ainasiart

@ainasiart 그래서 단위 테스트 중에 어떻게 작동합니까?
Nicholas Siegmundt

7

exe를 두 번 클릭하여 호출 해야하는 경우 이것을 사용합니다.

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

5
결과적으로 임의의 디렉토리를 얻을 수 있기 때문에 올바르지 않습니다.
amuliar

이 명령은 Environment.CurrentDirectory를 반환합니다.이 명령은 런타임에 임의의 경로로 변경 될 수 있으므로 신뢰할 수있는 솔루션이 아닙니다.
Yury Kozlov

7

나는 사용했다

System.AppDomain.CurrentDomain.BaseDirectory

응용 프로그램 폴더와 관련된 경로를 찾고 싶을 때. 이것은 ASP.Net 및 winform 응용 프로그램 모두에서 작동합니다. 또한 System.Web 어셈블리에 대한 참조가 필요하지 않습니다.


7

다음 줄은 응용 프로그램 경로를 제공합니다.

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

다음과 같은 상황에서 위의 솔루션이 올바르게 작동합니다.

  • 간단한 앱
  • Assembly.GetEntryAssembly ()가 null을 반환하는 다른 도메인
  • DLL은 Embedded 리소스에서 바이트 배열로로드되고 Assembly.Load (byteArrayOfEmbeddedDll)로 AppDomain에로드됩니다.
  • 모노 mkbundle번들 포함 (다른 방법은 작동하지 않음)

리눅스의 디버거에서 이것은 다음을 반환합니다 : / usr / share / dotnet
Vladimir

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

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 실행). 이 경우 GetModuleFileNameWin32 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 년 전에 한 번 이상 제안되었습니다.
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의 위치가 아닌 현재 디렉토리를 가져옵니다.
tenfour

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) 및 제한된 제어 (예 : 킬 등)를 제공합니다. *


-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.