Windows에서 임시 디렉토리를 만드시겠습니까?


126

Windows에서 임시 디렉터리 이름을 얻는 가장 좋은 방법은 무엇입니까? 임시 파일을 사용 GetTempPath하고 GetTempFileName생성 할 수 있다는 것을 알지만 mkdtemp, 임시 디렉토리를 생성하는 데 Linux / BSD 기능 과 동일한 기능이 있습니까?


이 질문은 찾기가 조금 어려워 보입니다. 특히 Stack Overflow 검색 상자에 "temp directory .net"과 같은 것을 입력하면 표시되지 않습니다. 답변은 지금까지 모든 .NET 답변이기 때문에 불행한 것 같습니다. ".net"태그를 추가 할 수 있다고 생각하십니까? (그리고 아마도 "directory"또는 "temporary-directory"태그일까요?) 아니면 제목에 ".NET"이라는 단어를 추가 할 수 있습니까? 질문 본문에서 "temp"와 "temporary"를 번갈아 표시 할 수도 있습니다. 따라서 더 짧은 형식을 검색하면 여전히 좋은 텍스트 검색 일치를 얻을 수 있습니다. 나는 이러한 일을 스스로 할 충분한 담당자가없는 것 같습니다. 감사.
Chris

글쎄, 나는 .NET이 아닌 대답을 찾고 있었기 때문에 그것을 생략하고 싶지만 당신이 제안한 다른 편집을했습니다. 감사.
Josh Kelley

@Josh Kelley : 방금 Win32 API를 다시 확인했으며 임시 경로를 가져오고 ramdom 파일 이름을 생성 한 다음 디렉터리를 만드는 유사한 접근 방식을 따르는 유일한 옵션이 있습니다.
Scott Dorman

답변:


230

아니요, mkdtemp에 해당하는 것은 없습니다. 가장 좋은 방법은 GetTempPathGetRandomFileName 의 조합을 사용하는 것입니다 .

다음과 유사한 코드가 필요합니다.

public string GetTemporaryDirectory()
{
   string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
   Directory.CreateDirectory(tempDirectory);
   return tempDirectory;
}

3
이건 좀 위험 해 보입니다. 특히 Path.Combine (Path.GetTempPath (), Path.GetRandomFileName ())이 이미 존재하는 디렉터리의 이름을 반환 할 가능성이 있습니다 (작지만 0이 아님). tempDirectory가 이미 존재하는 경우 Directory.CreateDirectory (tempDirectory)에서 예외가 발생하지 않으므로이 경우는 애플리케이션에서 감지되지 않습니다. 그리고 서로의 작업을 밟는 두 개의 응용 프로그램이있을 수 있습니다. .NET에 더 안전한 대안이 있습니까?
Chris

22
@Chris : GetRandomFileName 메서드는 폴더 이름이나 파일 이름으로 사용할 수있는 강력한 암호화 된 임의 문자열을 반환합니다. 이론적으로는 결과 경로가 이미 존재할 수 있지만이를 수행하는 다른 방법은 없습니다. 경로가 존재하는지 확인하고 Path.GetRandomFileName ()을 다시 호출하는지 확인하고 반복합니다.
Scott Dorman

5
@Chris : 예, 보안이 그 정도로 걱정된다면 다른 프로세스가 Path.Combine과 Directory.CreateDirectory 호출 사이에 디렉터리를 생성 할 가능성이 매우 적습니다.
Scott Dorman

8
GetRandomFileName은 도메인 크기가 (26 + 10) ^ 11 = ~ 57 비트임을 의미하는 11 개의 임의 소문자와 숫자를 생성합니다. 제곱하기 위해 항상 두 번의 전화를 걸 수 있습니다
Marty Neal

27
디렉토리가 존재하지 않는지 확인한 직후, 신은 우주를 일시 중지하고 잠입하여 작성하려는 모든 파일이 포함 된 동일한 디렉토리를 생성하여 앱이 폭발하여 하루를 망칠 수 있습니다.
Triynko

25

Path.GetTempFileName()디스크에 유효한 의사 임의 파일 경로를 제공하기 위해 해킹 한 다음 파일을 삭제하고 동일한 파일 경로로 디렉토리를 만듭니다.

이렇게하면 Scott Dorman의 답변에 대한 Chris의 의견에 따라 파일 경로를 while 또는 loop에서 사용할 수 있는지 확인할 필요가 없습니다.

public string GetTemporaryDirectory()
{
  string tempFolder = Path.GetTempFileName();
  File.Delete(tempFolder);
  Directory.CreateDirectory(tempFolder);

  return tempFolder;
}

정말로 암호 학적으로 안전한 임의의 이름이 필요한 경우 Scott의 대답을 수정하여 while을 사용하거나 루프를 수행하여 디스크에 경로를 계속 생성하려고 할 수 있습니다.


7

CoCreateGuid () 및 CreateDirectory ()와 같은 GUID 생성 함수 인 GetTempPath ()를 사용하고 싶습니다.

GUID는 고유성 가능성이 높도록 설계되었으며, 누군가가 GUID와 동일한 형식의 디렉터리를 수동으로 생성 할 가능성이 매우 낮습니다.


5

@Chris. 나도 임시 디렉토리가 이미 존재할 수 있다는 원격 위험에 집착했습니다. 무작위적이고 암호 학적으로 강력한 토론도 저를 완전히 만족시키지 못합니다.

내 접근 방식은 O / S가 두 번의 호출이 모두 성공하기 위해 파일을 생성하도록 허용해서는 안된다는 근본적인 사실을 기반으로합니다. .NET 디자이너가 디렉터리에 대한 Win32 API 기능을 숨기도록 선택했다는 것은 약간 놀랍습니다. 두 번째로 디렉터리를 만들려고하면 오류가 반환되기 때문에 훨씬 쉽게 디렉터리에 대한 Win32 API 기능을 숨길 수 있습니다. 내가 사용하는 것은 다음과 같습니다.

    [DllImport(@"kernel32.dll", EntryPoint = "CreateDirectory", SetLastError = true, CharSet = CharSet.Unicode)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CreateDirectoryApi
        ([MarshalAs(UnmanagedType.LPTStr)] string lpPathName, IntPtr lpSecurityAttributes);

    /// <summary>
    /// Creates the directory if it does not exist.
    /// </summary>
    /// <param name="directoryPath">The directory path.</param>
    /// <returns>Returns false if directory already exists. Exceptions for any other errors</returns>
    /// <exception cref="System.ComponentModel.Win32Exception"></exception>
    internal static bool CreateDirectoryIfItDoesNotExist([NotNull] string directoryPath)
    {
        if (directoryPath == null) throw new ArgumentNullException("directoryPath");

        // First ensure parent exists, since the WIN Api does not
        CreateParentFolder(directoryPath);

        if (!CreateDirectoryApi(directoryPath, lpSecurityAttributes: IntPtr.Zero))
        {
            Win32Exception lastException = new Win32Exception();

            const int ERROR_ALREADY_EXISTS = 183;
            if (lastException.NativeErrorCode == ERROR_ALREADY_EXISTS) return false;

            throw new System.IO.IOException(
                "An exception occurred while creating directory'" + directoryPath + "'".NewLine() + lastException);
        }

        return true;
    }

관리되지 않는 p / invoke 코드의 "비용 / 위험"이 가치가 있는지 여부를 결정할 수 있습니다. 대부분은 그렇지 않다고 말할 것이지만 적어도 지금은 선택권이 있습니다.

CreateParentFolder ()는 학생에게 연습으로 남겨집니다. Directory.CreateDirectory ()를 사용합니다. 디렉토리의 부모는 루트에있을 때 null이므로주의해야합니다.


5

나는 보통 이것을 사용합니다 :

    /// <summary>
    /// Creates the unique temporary directory.
    /// </summary>
    /// <returns>
    /// Directory path.
    /// </returns>
    public string CreateUniqueTempDirectory()
    {
        var uniqueTempDir = Path.GetFullPath(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()));
        Directory.CreateDirectory(uniqueTempDir);
        return uniqueTempDir;
    }

이 디렉토리 이름이 임시 경로에 존재하지 않는지 확인하려면이 고유 한 디렉토리 이름이 있는지 확인하고 실제로 존재하는 경우 다른 이름을 만들어야합니다.

그러나이 GUID 기반 구현으로 충분합니다. 이 경우 문제에 대한 경험이 없습니다. 일부 MS 응용 프로그램은 GUID 기반 임시 디렉터리도 사용합니다.


1

GetTempPath 는이를 수행하는 올바른 방법입니다. 이 방법에 대한 당신의 우려가 무엇인지 잘 모르겠습니다. 그런 다음 CreateDirectory 를 사용 하여 만들 수 있습니다.


한 가지 문제는 GetTempFileName이 0 바이트 파일을 생성한다는 것입니다. 대신 GetTempPath, GetRandomFileName 및 CreateDirectory를 사용해야합니다.
Scott Dorman

그것은 훌륭하고, 가능하며, 가능합니다. 코드를 제공하려고했지만 Dorman이 먼저 가져 왔고 올바르게 작동합니다.

1

다음은 임시 디렉토리 이름의 충돌 문제를 해결하기위한 좀 더 무차별적인 접근 방식입니다. 오류가없는 접근 방식은 아니지만 폴더 경로 충돌 가능성을 크게 줄입니다.

임시 디렉토리 이름에 이러한 정보를 표시하는 것은 바람직하지 않을 수 있지만 잠재적으로 다른 프로세스 또는 어셈블리 관련 정보를 디렉토리 이름에 추가하여 충돌 가능성을 줄일 수 있습니다. 폴더 이름이 더 무작위로 보이도록 시간 관련 필드가 결합되는 순서를 혼합 할 수도 있습니다. 저는 개인적으로 디버깅 중에 모두 찾기 쉽기 때문에 그대로 두는 것을 선호합니다.

string randomlyGeneratedFolderNamePart = Path.GetFileNameWithoutExtension(Path.GetRandomFileName());

string timeRelatedFolderNamePart = DateTime.Now.Year.ToString()
                                 + DateTime.Now.Month.ToString()
                                 + DateTime.Now.Day.ToString()
                                 + DateTime.Now.Hour.ToString()
                                 + DateTime.Now.Minute.ToString()
                                 + DateTime.Now.Second.ToString()
                                 + DateTime.Now.Millisecond.ToString();

string processRelatedFolderNamePart = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();

string temporaryDirectoryName = Path.Combine( Path.GetTempPath()
                                            , timeRelatedFolderNamePart 
                                            + processRelatedFolderNamePart 
                                            + randomlyGeneratedFolderNamePart);

0

위에서 언급했듯이 Path.GetTempPath ()는이를 수행하는 한 가지 방법입니다. Environment.GetEnvironmentVariable ( "TEMP")을 호출 할 수도 있습니다.사용자가 TEMP 환경 변수를 설정 한 경우 .

응용 프로그램에서 데이터를 유지하는 수단으로 임시 디렉터리를 사용할 계획이라면 구성 / 상태 / 기타를위한 저장소로 IsolatedStorage 를 사용해야합니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.