在Windows中创建临时目录?

Jos*_*ley 119 .net c# windows temporary-directory

在Windows中获取临时目录名称的最佳方法是什么?我看到我可以使用GetTempPathGetTempFileName创建一个临时文件,但有没有相当于Linux/BSD mkdtemp函数来创建一个临时目录?

Sco*_*man 219

不,没有相当于mkdtemp.最好的选择是使用GetTempPathGetRandomFileName的组合.

你需要类似这样的代码:

public string GetTemporaryDirectory()
{
   string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
   Directory.CreateDirectory(tempDirectory);
   return tempDirectory;
}
Run Code Online (Sandbox Code Playgroud)

  • @Chris:GetRandomFileName方法返回一个加密强大的随机字符串,可用作文件夹名称或文件名.我认为理论上可能的结果路径已经存在,但没有其他方法可以做到这一点.您可以检查路径是否存在,以及它是否再次调用Path.GetRandomFileName()并重复. (22认同)
  • 在您检查目录不存在之后,上帝可以暂停宇宙,潜入并使用您即将编写的所有相同文件创建相同的目录,从而导致您的应用程序爆炸,只是毁了您的一天. (20认同)
  • GetRandomFileName生成11个随机小写字母和数字,表示域大小为(26 + 10)^ 11 = ~57位.您可以随时拨打两个电话来对齐它 (8认同)
  • @Chris:是的,如果你担心这种程度的安全性,那么另一个进程可能会创建Path.Combine和Directory.CreateDirectory调用之间的目录. (5认同)
  • 这似乎有点危险.特别是,Path.Combine(Path.GetTempPath(),Path.GetRandomFileName())将返回已存在的目录的名称(小,但非零,对吧?).如果tempDirectory已经存在,则Directory.CreateDirectory(tempDirectory)不会抛出异常,因此应用程序将不会检测到这种情况.然后你可能有两个应用程序踩到彼此的工作.在.NET中有更安全的替代方案吗? (3认同)
  • @Scott 我认为如果您真的对安全很着迷,那么检查路径是否存在实际上是不够的。假设您调用 Directory.Exists(tempDirectory) 并了解到该目录尚不存在。此时,另一个进程可能会潜入并创建您将要创建的目录,然后再调用 Directory.CreateDirectory()。当控制权返回给您的应用程序时,您对 CreateDirectory 的调用不会引发异常,并且这两个应用程序最终会相互影响。在实践中似乎不太可能,但它仍然让我有点困扰。 (2认同)
  • 或者,您可以使用 C# 程序的进程 ID,该 ID 保证在系统上运行的进程之间是唯一的(因此与同一进程的另一个实例相比,*没有* 机会发生资源冲突)。以类似的方式,您可以在该 pid 命名的目录中唯一标识单个线程的资源。然后用`Directory.CreateDirectory` 创建目录是幂等的,所以你不需要测试是否存在。如果由于某种原因你让人们访问你的文件系统,以至于你唯一的防御是随机命名的目录,祝你好运...... (2认同)

Ste*_*sen 20

Path.GetTempFileName()讨厌在磁盘上给我一个有效的伪随机文件路径,然后删除该文件,并创建一个具有相同文件路径的目录.

根据Chris对Scott Dorman的回答,这可以避免检查文件路径是否在一段时间或循环中可用的需要.

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

  return tempFolder;
}
Run Code Online (Sandbox Code Playgroud)

如果您确实需要加密安全的随机名称,您可能需要调整Scott的答案以使用while或do循环来继续尝试在磁盘上创建路径.

  • 是否还有可能有人在“Delete”和“CreateDirectory”之间创建相同的目录? (3认同)

Leg*_*nds 12

自 .NET 7 起:

Directory.CreateTempSubdirectory();
Run Code Online (Sandbox Code Playgroud)

C:\Users\用户名\AppData\Local\Temp\yafdhmxq.ngy


使用文件夹名称的自定义前缀

Directory.CreateTempSubdirectory("prefix_"); // prepends "prefix_" to the dir name
Run Code Online (Sandbox Code Playgroud)

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


par*_*820 11

我使用了一些答案并GetTmpDirectory以这种方式实现了方法。

public string GetTmpDirectory()
{
    string tmpDirectory;

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

    Directory.CreateDirectory(tmpDirectory);
    return tmpDirectory;
}
Run Code Online (Sandbox Code Playgroud)


小智 7

我喜欢使用GetTempPath(),像CoCreateGuid()和CreateDirectory()这样的GUID创建函数.

GUID被设计为具有很高的唯一性概率,并且非常不可能有人手动创建具有与GUID相同形式的目录(如果他们这样做,那么CreateDirectory()将失败指示其存在.)


And*_*son 5

@克里斯。我也很迷恋可能已经存在一个临时目录的远程风险。关于随机性和加密性强的讨论也没有完全使我满意。

我的方法基于这样一个基本事实,即操作系统不允许两个调用创建一个文件才能成功。.NET设计人员选择隐藏目录的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;
    }
Run Code Online (Sandbox Code Playgroud)

您可以确定非托管p /调用代码的“成本/风险”是否值得。大多数人会说不是,但是至少您现在可以选择。

CreateParentFolder()作为练习留给学生。我使用Directory.CreateDirectory()。小心获取目录的父目录,因为在根目录时该目录为null。


小智 5

我通常使用这个:

    /// <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;
    }
Run Code Online (Sandbox Code Playgroud)

如果您想绝对确定临时路径中不存在此目录名称,则需要检查此唯一目录名称是否存在,如果确实存在,则尝试创建另一个目录名称。

但是这种基于 GUID 的实现就足够了。在这种情况下,我没有任何问题的经验。一些 MS 应用程序也使用基于 GUID 的临时目录。