在 Windows 中创建临时目录?

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

103597 次浏览

GetTempPath 是正确的方法; 我不知道您对此方法的担忧是什么。然后您可以使用 创建目录来制作它。

不,没有等效于 mkdtemp。最好的选择是使用 GetTempPath名称的组合。

您将需要类似于下面这样的代码:

public string GetTemporaryDirectory()
{
string tempDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
Directory.CreateDirectory(tempDirectory);
return tempDirectory;
}

如上所述,路径。GetTempPath ()是这样做的一种方法。如果用户设置了 TEMP 环境变量,你也可以调用 环境变量(“ TEMP”)

如果您打算使用 temp 目录作为在应用程序中持久化数据的方法,那么您可能应该考虑使用 独立存储作为配置/状态/等的存储库。.

我喜欢使用 GetTempPath () ,这是一个创建 GUID 的函数,比如 CoCreateGuid ()和 CreateDirectory ()。

GUID 被设计为具有很高的唯一性概率,而且很难有人手动创建与 GUID 具有相同表单的目录(如果他们这样做,CreateDirectory ()将无法指示它的存在)

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

这避免了检查文件路径是否在 while 或循环中可用的需要,这是根据 Chris 对 Scott Dorman 的回答的评论。

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


return tempFolder;
}

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

这里有一种更加强力的方法来解决临时目录名称的冲突问题。这种方法并非万无一失,但它显著降低了文件夹路径冲突的可能性。

可以在目录名称中添加其他进程或程序集相关信息,从而降低冲突的可能性,尽管在临时目录名称中显示此类信息可能并不理想。还可以混合使用与时间相关的字段的组合顺序,使文件夹名称看起来更随机。就我个人而言,我更喜欢这样做,因为这样更容易在调试过程中找到它们。

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);

@ Chris.我也很担心临时目录可能已经存在的远程风险。关于随机性和加密强度的讨论也不能完全令我满意。

我的方法基于这样一个基本事实,即操作系统不能允许两次调用来创建一个文件,以使两次调用都成功。令人有点惊讶的是。NET 设计人员选择隐藏目录的 Win32API 功能,这使得这更加容易,因为当您第二次尝试创建目录时,它确实会返回一个错误。以下是我使用的方法:

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

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

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

我通常用这个:

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

如果您想要绝对确定这个目录名在临时路径中不存在,那么您需要检查这个唯一的目录名是否存在,并尝试创建另一个目录名(如果它真的存在)。

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

我使用了一些答案,并以这种方式实现了 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;
}