165

What's the best way to get a temp directory name in Windows? I see that I can use GetTempPath and GetTempFileName to create a temporary file, but is there any equivalent to the Linux / BSD mkdtemp function for creating a temporary directory?

3
  • This question seems a little hard to find. In particular, it doesn't show up if you type things like "temp directory .net" in the Stack Overflow search box. That seems unfortunate, since the answers are so far all .NET answers. Do you think you could add the ".net" tag? (And maybe the "directory" or "temporary-directory" tag?) Or maybe add the word ".NET" to the title? Maybe also in the question body alternate saying "temp" with "temporary" -- so if you search for the shorter form you'll still get a good text search match. I don't seem to have enough rep to do these things myself. Thanks.
    – Chris
    Commented Aug 20, 2009 at 18:40
  • Well, I was looking for a non-.NET answer, so I'd prefer to leave that out, but I made the other edits you suggested. Thanks. Commented Aug 20, 2009 at 21:36
  • @Josh Kelley: I just double-checked the Win32 API and the only options there are to follow a similar approach of getting the temp path, generating a ramdom file name, and then creating a directory. Commented Aug 20, 2009 at 23:15

10 Answers 10

294

No, there is no equivalent to mkdtemp. The best option is to use a combination of GetTempPath and GetRandomFileName.

You would need code similar to this:

public string GetTemporaryDirectory()
{
    string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());

    if(File.Exist(tempDirectory)) {
        return GetTemporaryDirectory();
    } else {
        Directory.CreateDirectory(tempDirectory);
        return tempDirectory;
    }
}
13
  • 6
    This seems a little dangerous. In particular, there's a chance (small, but non-zero, right?) that Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) will return the name of a directory that already exists. Since Directory.CreateDirectory(tempDirectory) won't throw an exception if tempDirectory already exists, this case won't be detected by your application. And then you may have two applications stepping on each other's work. Is there any safer alternative in .NET?
    – Chris
    Commented Aug 20, 2009 at 18:31
  • 30
    @Chris: The GetRandomFileName method returns a cryptographically strong, random string that can be used as either a folder name or a file name. I suppose it's theoretically possible that the resulting path could already exist, but there are no other ways to do this. You could check to see if the path exists, and if it does call Path.GetRandomFileName() again, and repeat. Commented Aug 20, 2009 at 19:49
  • 6
    @Chris: Yes, if you are worried about security to that extent there is a very slim chance that another process could create the directory between the Path.Combine and the Directory.CreateDirectory calls. Commented Aug 20, 2009 at 23:06
  • 8
    GetRandomFileName generates 11 random lowercase letters and numbers meaning the domain size is (26+10)^11 = ~57 bits. You can always make two calls to square it
    – Marty Neal
    Commented Jul 25, 2013 at 17:05
  • 42
    Just after you check that the directory does not exist, god could pause the universe, sneak in and create the same directory with all the same files you're about to write, causing your app to blow up, just to ruin your day.
    – Triynko
    Commented Feb 9, 2016 at 16:19
30

I hack Path.GetTempFileName() to give me a valid, pseudo-random filepath on disk, then delete the file, and create a directory with the same file path.

This avoids the need for checking if the filepath is available in a while or loop, per Chris' comment on Scott Dorman's answer.

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

  return tempFolder;
}

If you truly need a cryptographically secure random name, you may want to adapt Scott's answer to use a while or do loop to keep trying to create a path on disk.

1
  • 3
    Isn't there still a chance that someone creates the same directory between the Delete and the CreateDirectory?
    – Nick
    Commented Apr 14, 2021 at 9:21
20

Since .NET 7:

Directory.CreateTempSubdirectory();

C:\Users\USERNAME\AppData\Local\Temp\yafdhmxq.ngy


Using a custom prefix for the folder name

Directory.CreateTempSubdirectory("prefix_"); // prepends "prefix_" to the created dir name

C:\Users\USERNAME\AppData\Local\Temp\prefix_yrlbuecv.2lc

11

I used some of the answers and implemented GetTmpDirectory method this way.

public string GetTmpDirectory()
{
    string tmpDirectory;

    do
    {
        tmpDirectory = Path.Combine(Path.GetTempPath(), Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));
    } while (Directory.Exists(tmpDirectory));

    Directory.CreateDirectory(tmpDirectory);
    return tmpDirectory;
}
1
  • Throw a || File.Exists(tempDirectory) in there and this is perfect. Aside from the unecessary abbreviation from temp to tmp. Do you really need to save that one character?
    – HackSlash
    Commented Aug 9, 2023 at 17:52
8

I like to use GetTempPath(), a GUID-creation function like CoCreateGuid(), and CreateDirectory().

A GUID is designed to have a high probability of uniqueness, and it's also highly improbable that someone would manually create a directory with the same form as a GUID (and if they do then CreateDirectory() will fail indicating its existence.)

7

@Chris. I too was obsessed with the remote risk that a temporary directory might already exist. The discussions about random and cryptographically strong don’t completely satisfy me either.

My approach builds on the fundamental fact that the O/S must not allow 2 calls to create a file to both succeed. It is a little surprising that .NET designers chose to hide the Win32 API functionality for directories, which makes this much easier, because it does return an error when you attempt to create a directory for the second time. Here is what I use:

    [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;
    }

You get to decide whether the "cost/risk" of unmanaged p/invoke code is worth it. Most would say it is not, but at least you now have a choice.

CreateParentFolder() is left as an exercise to the student. I use Directory.CreateDirectory(). Be careful getting the parent of a directory, since it is null when at the root.

7

I usually use this:

    /// <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;
    }

If you want to be absolutely sure that this directory name will not exists in temp path then you need to check if this unique directory name exists and try to create other one if it really exists.

But this GUID-based implementation is sufficient. I have no experience with any problem in this case. Some MS applications uses GUID based temp directories too.

1

Here is a somewhat more brute-force approach to resolving the collision problem for temporary directory names. It is not an infallible approach, but it reduces significantly the chances of a folder path collision.

One could potentially add other process or assembly related information to the directory name to make the collision even less likely, although making such an information visible on the temporary directory name might not be desirable. One could also mix the order with which the time-related fields are combined to make the folder names look more random. I personally prefer to leave it that way simply because it is easier for me to find them all during debugging.

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

As mentioned above, Path.GetTempPath() is one way to do it. You could also call Environment.GetEnvironmentVariable("TEMP") if the user has a TEMP environment variable set up.

If you are planning on using the temp directory as a means of persisting data in the application, you probably should look at using IsolatedStorage as a repository for configuration/state/etc...

-1

GetTempPath is the correct way of doing it; I'm not sure what your concern about this method is. You can then use CreateDirectory to make it.

2
  • One problem is that GetTempFileName will create a zero-byte file. You need to use GetTempPath, GetRandomFileName and CreateDirectory instead. Commented Nov 10, 2008 at 16:57
  • Which is fine, possible, and doable. I was going to provide code but Dorman got it before me, and it works correctly.
    – user1228
    Commented Nov 10, 2008 at 17:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.