在 Windows 中创建临时目录?

发布于 2024-07-08 08:07:22 字数 286 浏览 14 评论 0 原文

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

扶醉桌前 2024-07-15 08:07:22

不,没有与 mkdtemp 等效的东西。 最好的选择是使用 GetTempPathGetRandomFileName

您将需要与此类似的代码:

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

    if(File.Exist(tempDirectory)) {
        return GetTemporaryDirectory();
    } else {
        Directory.CreateDirectory(tempDirectory);
        return tempDirectory;
    }
}

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;
    }
}
凉薄对峙 2024-07-15 08:07:22

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

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

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

  return tempFolder;
}

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

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.

赠佳期 2024-07-15 08:07:22

自 .NET 7 起:

Directory.CreateTempSubdirectory();

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


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

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

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

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

迷爱 2024-07-15 08:07:22

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

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;
}
王权女流氓 2024-07-15 08:07:22

我喜欢使用 GetTempPath()、GUID 创建函数,如 CoCreateGuid() 和 CreateDirectory()。

GUID 被设计为具有很高的唯一性概率,而且某人也不太可能手动创建与 GUID 形式相同的目录(如果他们这样做,则 CreateDirectory() 将失败,表明其存在。)

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

鹿港巷口少年归 2024-07-15 08:07:22

@克里斯。 我也对临时目录可能已经存在的远程风险很着迷。 关于随机性和加密强度的讨论也不完全令我满意。

我的方法建立在这样一个基本事实之上:操作系统不得允许两次创建文件的调用都成功。 有点令人惊讶的是,.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;
    }

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

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

@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.

鞋纸虽美,但不合脚ㄋ〞 2024-07-15 08:07:22

我通常使用这个:

    /// <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 的临时目录。

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.

各自安好 2024-07-15 08:07:22

这是解决临时目录名称冲突问题的更暴力的方法。 这不是一种万无一失的方法,但它显着减少了文件夹路径冲突的机会。

人们可以潜在地将其他进程或程序集相关信息添加到目录名称中,以降低发生冲突的可能性,尽管使此类信息在临时目录名称上可见可能并不理想。 人们还可以混合时间相关字段的组合顺序,以使文件夹名称看起来更加随机。 我个人更喜欢保持这种方式,因为这样我在调试过程中更容易找到它们。

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

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);
我为君王 2024-07-15 08:07:22

如上所述,Path.GetTempPath() 是一种方法。 如果用户设置了 TEMP 环境变量。

如果您计划使用临时目录作为在应用程序中保存数据的方法,您可能应该考虑使用 IsolatedStorage 作为配置/状态/等的存储库...

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...

自找没趣 2024-07-15 08:07:22

GetTempPath 是正确的方法; 我不确定您对这种方法的担忧是什么。 然后,您可以使用 CreateDirectory 来创建它。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文