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

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



답변

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

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

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


답변

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

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

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

  return tempFolder;
}

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


답변

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

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


답변

@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이므로주의해야합니다.


답변

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

    /// <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 기반 임시 디렉터리도 사용합니다.


답변

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


답변

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

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

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