2008-08-19 8 views
28

저는 응용 프로그램을위한 여러 개의 임시 폴더를 만들어야하는 프로그램을 만들고 있습니다. 사용자가 볼 수 없습니다. 이 응용 프로그램은 VB.net로 작성되었습니다. 내가 점진적 폴더 이름이나 임의의 번호가 매겨진 폴더 이름과 같은 몇 가지 방법을 생각할 수 있지만, 다른 사람들이이 문제를 해결하는 방법을 궁금해하고 있었습니까?임시 폴더 만들기

답변

26

업데이트 : 추가 File.Exists 코멘트 (2012 6 월-19)

가 여기에 내가 VB.NET에서 사용했습니다 무엇에 따라 확인한다. 본질적으로 제시된 것과 동일하지만, 보통 폴더를 즉시 생성하고 싶지 않았습니다.

GetRandomFilename을 사용하면 파일을 만들지 않으므로 파일이 아닌 다른 이름으로 이름을 사용하는 경우 정리할 필요가 없습니다. 폴더 이름으로 사용하는 것과 같습니다.

Private Function GetTempFolder() As String 
    Dim folder As String = Path.Combine(Path.GetTempPath, Path.GetRandomFileName) 
    Do While Directory.Exists(folder) or File.Exists(folder) 
     folder = Path.Combine(Path.GetTempPath, Path.GetRandomFileName) 
    Loop 

    Return folder 
End Function 

임의 파일 이름 예 :

C : \ 문서 및 설정 \ 로컬 설정 \ 사용자 이름 \ 임시 \의 u3z5e0co.tvq 여기


은을 얻기 위해 GUID를 사용하여 변형입니다 임시 폴더 이름.

Private Function GetTempFolderGuid() As String 
    Dim folder As String = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString) 
    Do While Directory.Exists(folder) or File.Exists(folder) 
     folder = Path.Combine(Path.GetTempPath, Guid.NewGuid.ToString) 
    Loop 

    Return folder 
End Function 

GUID 예 : 2dbc6db7-2d45-4b75-b27f-0bd492c60496

+0

루프 조건에'Directory.Exists' 외에'File.Exists'가 포함되어서는 안됩니까? 'Path.GetTempPath'에 기존 temp_file_이있을 수 있으며 이는 디렉토리 생성을 방해합니다. –

+0

네 말이 맞아. File.Exists() 체크를 포함하도록 답변을 업데이트하겠습니다. – Rick

+0

GetTempFileName이 파일을 생성하는 것과 같은 이유로 ** 함수 내에서 ** 폴더를 생성해야합니다. 다른 사람이 수행 할 확률이 0이되도록해야합니다. – Jaykul

1

폴더의 이름이 의미있는 이름 일 필요는 없지만 GUID를 사용하는 것은 어떻습니까?

2

임시 폴더 이름에 대한 GUID를 생성 할 수 있습니다.

20

당신은 System.IO.Path.GetTempFileName()

디스크에 고유 한 이름, 0 바이트 임시 파일을 작성하고 전체 경로를 반환 사용해야합니다 그 파일의

만 임시 폴더 정보를 얻을 수 System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName())을 사용하고있다

그들은 윈도우 임시 폴더에 생성됩니다에 폴더를 생성하고 그 가장 좋은 방법을 같은

+1

아니요 ** 이렇게하십시오. 'System.IO.Path.GetTempFileName'에서'System.IO.Path.GetDirectoryName'을 호출하면'System.IO.Path.GetTempPath'를 최악으로 대체 할 수 있습니다. 왜냐하면 남겨진 파일을 생성하기 때문입니다. – Jaykul

3

뭔가 생각입니다 수 있습니다 .. .

using System.IO; 

string path = Path.GetTempPath() + Path.GetRandomFileName(); 
while (Directory.Exists(path)) 
path = Path.GetTempPath() + Path.GetRandomFileName(); 

Directory.CreateDirectory(path); 
최고의 이럴 작동 @ 아담 - 라이트 및 pix0r에서
+0

디렉토리를 만들지 못하면 try-catch를 사용하여 루프를 다시 입력하십시오. – Jaykul

1

결합 답변 :

,536을

using System.IO; 

string path = Path.GetTempPath() + Path.GetRandomFileName(); 

while (Directory.Exists(path)) 
    path = Path.GetTempPath() + Path.GetRandomFileName(); 

File.Delete(path); 
Directory.CreateDirectory(path); 
0

System.IO.Path.GetTempFileName을 사용할 때의 장점은 사용자의 로컬 (즉, 로밍이 아닌) 경로에있는 파일이라는 점입니다. 이는 사용 권한 및 보안상의 이유로 정확하게 원하는 곳입니다.

8

그냥 명확하게 \ 문서 및 설정 \ 로컬 설정 \ 사용자 이름 \ 임시 \ :

C

System.IO.Path.GetTempPath() 

은 임시 폴더에 대한 폴더 경로 만 반환합니다.

System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName()) 

가 중복 :

System.IO.Path.GetTempFileName() 

는 완전한 파일 (경로 포함) 이름 때문에이를 반환합니다.

+6

GetTempPath와 GetTempFileName은 완전히 다른 두 가지 방법입니다. GetTempPath는 시스템의 임시 폴더 위치를 반환하고 GetTempFileName은 임시 길이가 0 인 파일을 만들고 해당 파일의 전체 경로를 반환합니다. –

8

때 가능한 경쟁 조건이있다 :

  • 그것을 삭제 GetTempFileName()에 임시 파일을 생성하고 같은 이름의 폴더를 만들고, 또는
  • 폴더 이름을 GetRandomFileName() 또는 Guid.NewGuid.ToString를 사용하여 작성 나중에 폴더

GetTempFileName()과 함께 삭제가 발생하면 다른 응용 프로그램이 동일한 이름의 임시 파일을 성공적으로 만들 수 있습니다. 그러면 CreateDirectory()이 실패합니다.

마찬가지로 GetRandomFileName()을 호출하고 다른 프로세스에서 동일한 이름의 파일이나 디렉토리를 만들면 CreateDirectory()이 실패 할 수 있습니다.

대부분의 응용 프로그램에서는 경쟁 디렉터리로 인해 임시 디렉터리가 실패 할 수 있습니다. 그것은 결국 매우 드문 일입니다. 그들에게는이 종족들이 종종 무시 당할 수 있습니다.

유닉스 쉘 스크립팅 세계에서 임시 파일과 디렉토리를 안전한 경주없이 만드는 것은 큰 문제입니다. 많은 컴퓨터에는 여러 명의 (적대적인) 사용자가 있습니다 - 공유 웹 호스트라고 생각하고 많은 스크립트와 응용 프로그램은 공유/tmp 디렉토리에 임시 파일과 디렉토리를 안전하게 만들어야합니다. 셸 스크립트에서 임시 디렉터리를 안전하게 만드는 방법에 대한 설명은 Safely Creating Temporary Files in Shell Scripts을 참조하십시오.

6

@JonathanWright pointed out으로, 경쟁 조건은 솔루션 존재합니다

  • GetTempFileName()와 임시 파일을 만들고 삭제하고,
  • 사용 GetRandomFileName() 또는 Guid.NewGuid.ToString이를 만들 수있는 같은 이름의 폴더를 생성 임의의 폴더 이름, 존재 여부 확인, 그렇지 않은 경우 생성하십시오.

그러나 Transactional NTFS (TxF) API를 사용하여 고유 한 임시 디렉터리를 원자 적으로 만들 수 있습니다.

TxF에는 플랫폼 호출을 통해 호출 할 수있는 CreateDirectoryTransacted() 함수가 있습니다.이를 위해, 나는 CreateFileTransacted()를 호출 Mohammad Elsheimy's code 적응 :

// using System.ComponentModel; 
// using System.Runtime.InteropServices; 
// using System.Transactions; 

[ComImport] 
[Guid("79427a2b-f895-40e0-be79-b57dc82ed231")] 
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
public interface IKernelTransaction 
{ 
    void GetHandle(out IntPtr pHandle); 
} 

// 2.2 Win32 Error Codes <http://msdn.microsoft.com/en-us/library/cc231199.aspx> 
public const int ERROR_PATH_NOT_FOUND = 0x3; 
public const int ERROR_ALREADY_EXISTS = 0xb7; 
public const int ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION = 0x1aaf; 

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 
public static extern bool CreateDirectoryTransacted(string lpTemplateDirectory, string lpNewDirectory, IntPtr lpSecurityAttributes, IntPtr hTransaction); 

/// <summary> 
/// Creates a uniquely-named directory in the directory named by <paramref name="tempPath"/> and returns the path to it. 
/// </summary> 
/// <param name="tempPath">Path of a directory in which the temporary directory will be created.</param> 
/// <returns>The path of the newly-created temporary directory within <paramref name="tempPath"/>.</returns> 
public static string GetTempDirectoryName(string tempPath) 
{ 
    string retPath; 

    using (TransactionScope transactionScope = new TransactionScope()) 
    { 
     IKernelTransaction kernelTransaction = (IKernelTransaction)TransactionInterop.GetDtcTransaction(Transaction.Current); 
     IntPtr hTransaction; 
     kernelTransaction.GetHandle(out hTransaction); 

     while (!CreateDirectoryTransacted(null, retPath = Path.Combine(tempPath, Path.GetRandomFileName()), IntPtr.Zero, hTransaction)) 
     { 
      int lastWin32Error = Marshal.GetLastWin32Error(); 
      switch (lastWin32Error) 
      { 
       case ERROR_ALREADY_EXISTS: 
        break; 
       default: 
        throw new Win32Exception(lastWin32Error); 
      } 
     } 

     transactionScope.Complete(); 
    } 
    return retPath; 
} 

/// <summary> 
/// Equivalent to <c>GetTempDirectoryName(Path.GetTempPath())</c>. 
/// </summary> 
/// <seealso cref="GetTempDirectoryName(string)"/> 
public static string GetTempDirectoryName() 
{ 
    return GetTempDirectoryName(Path.GetTempPath()); 
} 
0
Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString)) 
0

@JonathanWright 이미 폴더가있을 때 CreateDirectory이 실패합니다 제안합니다. Directory.CreateDirectory를 읽으면 '지정된 경로에있는 디렉토리가 이미 존재하는지 여부에 관계없이이 개체가 반환됩니다.'라는 메시지가 표시됩니다. 의미는 당신이 존재하는 수표와 실제로 만드는 사이에 만들어진 폴더를 감지하지 않습니다.

@DanielTrebbien에서 제안한 CreateDirectoryTransacted()가 마음에 들지만이 함수는 더 이상 사용되지 않습니다.

내가보기에 유일한 해결책은 cp api를 사용하고 'CreateDirectory'을 호출하는 것입니다. 실제로 전체 경쟁 조건을 확실히 알아야 할 경우 폴더가 존재하면 오류가 발생합니다. 그러면 다음과 같은 결과가 발생합니다.

Private Function GetTempFolder() As String 
    Dim folder As String 
    Dim succes as Boolean = false 
    Do While not succes 
     folder = Path.Combine(Path.GetTempPath, Path.GetRandomFileName) 
     success = c_api_create_directory(folder) 
    Loop 
    Return folder 
End Function 
+0

무한히 루핑하는 것이 합리적입니다. – Matt