[ACCEPTED]-Creating temporary folders-io
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
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
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.
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()
orGuid.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.
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()
orGuid.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());
}
Something like...
using System.IO;
string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
path = Path.GetTempPath() + Path.GetRandomFileName();
Directory.CreateDirectory(path);
0
You could generate a GUID for your temporary 1 folder names.
As long as the name of the folder doesn't 2 need to be meaningful, how about using a 1 GUID for them?
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
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);
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.
Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))
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
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.