[ACCEPTED]-Creating temporary folders-io

Accepted answer
Score: 29

Update: Added File.Exists check per comment (2012-Jun-19)

Here's 11 what I've used in VB.NET. Essentially 10 the same as presented, except I usually 9 didn't want to create the folder immediately.

The 8 advantage to use GetRandomFilename is that it doesn't create 7 a file, so you don't have to clean up if 6 your using the name for something other 5 than a file. Like using it for folder name.

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

Random Filename 4 Example:

C:\Documents and Settings\username\Local 3 Settings\Temp\u3z5e0co.tvq


Here's a variation 2 using a Guid to get the temp folder name.

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 Example:

C:\Documents 1 and Settings\username\Local Settings\Temp\2dbc6db7-2d45-4b75-b27f-0bd492c60496

Score: 19

You have to use System.IO.Path.GetTempFileName()

Creates a uniquely named, zero-byte 6 temporary file on disk and returns the full 5 path of that file.

You can use System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName()) to get only 4 the temp folder information, and create 3 your folders in there

They are created in 2 the windows temp folder and that's consider 1 a best practice

Score: 8

Just to clarify:

System.IO.Path.GetTempPath()

returns just the folder 3 path to the temp folder.

System.IO.Path.GetTempFileName()

returns the fully 2 qualified file name (including the path) so 1 this:

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

is redundant.

Score: 8

There's a possible race condition when:

  • creating a temp file with GetTempFileName(), deleting it, and making a folder with the same name, or
  • using GetRandomFileName() or Guid.NewGuid.ToString to name a folder and creating the folder later

With 19 GetTempFileName() after the delete occurs, another application 18 could successfully create a temp file with 17 the same name. The CreateDirectory() would then fail.

Similarly, between 16 calling GetRandomFileName() and creating the directory another 15 process could create a file or directory 14 with the same name, again resulting in CreateDirectory() failing.

For 13 most applications it's OK for a temp directory 12 to fail due to a race condition. It's extremely 11 rare after all. For them, these races can 10 often be ignored.

In the Unix shell scripting 9 world, creating temp files and directories 8 in a safe race-free way is a big deal. Many 7 machines have multiple (hostile) users -- think 6 shared web host -- and many scripts and 5 applications need to safely create temp 4 files and directories in the shared /tmp 3 directory. See Safely Creating Temporary Files in Shell Scripts for a discussion on how 2 to safely create temp directories from shell 1 scripts.

Score: 6

As @JonathanWright pointed out, race conditions exist 5 for the solutions:

  • Create a temporary file with GetTempFileName(), delete it, and create a folder with the same name
  • Use GetRandomFileName() or Guid.NewGuid.ToString to create a random folder name, check whether it exists, and create it if not.

It is possible, however, to 4 create a unique temporary directory atomically 3 by utilizing the Transactional NTFS (TxF) API.

TxF has a CreateDirectoryTransacted() function 2 that can be invoked via Platform Invoke. To 1 do this, I adapted Mohammad Elsheimy's code for calling CreateFileTransacted():

// 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());
}
Score: 3

Something like...

using System.IO;

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

Directory.CreateDirectory(path);

0

Score: 2

You could generate a GUID for your temporary 1 folder names.

Score: 1

As long as the name of the folder doesn't 2 need to be meaningful, how about using a 1 GUID for them?

Score: 1

You can use GetTempFileName to create a temporary file, then 3 delete and re-create this file as a directory 2 instead.

Note: link didn't work, copy/paste 1 from: http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

Score: 1

Combined answers from @adam-wright and pix0r 1 will work the best IMHO:


using System.IO;

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

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

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

The advantage to using System.IO.Path.GetTempFileName 4 is that it will be a file in the user's 3 local (i.e., non-roaming) path. This is 2 exactly where you would want it for permissions 1 and security reasons.

Score: 0
Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))

0

Score: 0

@JonathanWright suggests CreateDirectory 14 will fail when there is already a folder. If 13 I read Directory.CreateDirectory it says 12 'This object is returned regardless of whether 11 a directory at the specified path already 10 exists.' Meaning you do not detect a folder 9 created between check exists and actually 8 creating.

I like the CreateDirectoryTransacted() suggested 7 by @DanielTrebbien but this function is 6 deprecated.

The only solution I see that 5 is left is to use the c api and call the 4 'CreateDirectory' there as it does error if the folder 3 exists if you really need to be sure to 2 cover the whole race condition. That would 1 result in something like this:

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

More Related questions