创建临时文件夹

时间:2008-08-19 18:14:14

标签: .net io

我正在开发一个需要为应用程序创建多个临时文件夹的程序。这些将不会被用户看到。该应用程序是用VB.net编写的。我可以想到几种方法,比如增量文件夹名称或随机编号的文件夹名称,但我想知道其他人如何解决这个问题?

13 个答案:

答案 0 :(得分:26)

更新:已添加File.Exists检查每条评论(2012年6月19日)

这是我在VB.NET中使用的内容。基本上与呈现的相同,除了我通常不想立即创建文件夹。

使用GetRandomFilename的好处是它不会创建文件,因此如果您使用的名称不是文件,则无需清理。就像将它用于文件夹名称一样。

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

随机文件名示例:

C:\ Documents and Settings \ username \ Local Settings \ Temp \ u3z5e0co.tvq


这是使用Guid获取临时文件夹名称的变体。

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 示例:

C:\ Documents and Settings \ username \ Local Settings \ Temp \ 2dbc6db7-2d45-4b75-b27f-0bd492c60496

答案 1 :(得分:20)

您必须使用System.IO.Path.GetTempFileName()

  

在磁盘上创建一个唯一命名的零字节临时文件,并返回该文件的完整路径。

您可以使用System.IO.Path.GetDirectoryName(System.IO.Path.GetTempFileName())仅获取临时文件夹信息,并在其中创建文件夹

它们是在windows temp文件夹中创建的,这是一种最佳实践

答案 2 :(得分:8)

只是为了澄清:

System.IO.Path.GetTempPath()

只返回临时文件夹的文件夹路径。

System.IO.Path.GetTempFileName()

返回完全限定的文件名(包括路径),所以:

System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName())

是多余的。

答案 3 :(得分:8)

在以下情况下可能存在竞争条件:

  • 使用GetTempFileName()创建临时文件,删除它,并创建一个具有相同名称的文件夹,或
  • 使用GetRandomFileName()Guid.NewGuid.ToString命名文件夹并稍后创建文件夹

删除发生后GetTempFileName(),另一个应用程序可以成功创建具有相同名称的临时文件。然后CreateDirectory()会失败。

同样,在调用GetRandomFileName()和创建目录之间,另一个进程可能会创建一个具有相同名称的文件或目录,再次导致CreateDirectory()失败。

对于大多数应用程序,临时目录由于竞争条件而失败是可以的。毕竟这是非常罕见的。对他们来说,这些比赛经常被忽略。

在Unix shell脚本世界中,以安全的无竞争方式创建临时文件和目录是一件大事。许多机器有多个(恶意)用户 - 想想共享的Web主机 - 许多脚本和应用程序需要在shared / tmp目录中安全地创建临时文件和目录。有关如何从shell脚本安全地创建临时目录的讨论,请参阅Safely Creating Temporary Files in Shell Scripts

答案 4 :(得分:6)

作为@JonathanWright pointed out,解决方案存在竞争条件:

  • 使用GetTempFileName()创建一个临时文件,将其删除,然后创建一个名称相同的文件夹
  • 使用GetRandomFileName()Guid.NewGuid.ToString创建随机文件夹名称,检查其是否存在,如果不存在则创建。

但是,可以使用Transactional NTFS(TxF)API以原子方式创建唯一的临时目录。

TxF有一个CreateDirectoryTransacted()函数,可以通过Platform Invoke调用。为此,我调整了Mohammad Elsheimy's code来调用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());
}

答案 5 :(得分:3)

像...一样的东西。

using System.IO;

string path = Path.GetTempPath() + Path.GetRandomFileName();
while (Directory.Exists(path))
 path = Path.GetTempPath() + Path.GetRandomFileName();

Directory.CreateDirectory(path);

答案 6 :(得分:2)

您可以为临时文件夹名称生成GUID。

答案 7 :(得分:1)

只要文件夹的名称不需要有意义,那么为它们使用GUID怎么样?

答案 8 :(得分:1)

您可以使用GetTempFileName创建临时文件,然后删除并重新创建此文件作为目录。

注意:链接不起作用,请复制/粘贴:http://msdn.microsoft.com/en-us/library/aa364991(VS.85).aspx

答案 9 :(得分:1)

来自@ adam-wright和pix0r的综合答案将是最好的恕我直言:


using System.IO;

string path = Path.GetTempPath() + Path.GetRandomFileName();

while (Directory.Exists(path)) 
  path = Path.GetTempPath() + Path.GetRandomFileName();

File.Delete(path);
Directory.CreateDirectory(path);

答案 10 :(得分:0)

使用System.IO.Path.GetTempFileName的优点是它将是用户本地(即非漫游)路径中的文件。出于权限和安全原因,这正是您所希望的位置。

答案 11 :(得分:0)

Dim NewFolder = System.IO.Directory.CreateDirectory(IO.Path.Combine(IO.Path.GetTempPath, Guid.NewGuid.ToString))

答案 12 :(得分:0)

@JonathanWright建议CreateDirectory在已有文件夹时失败。如果我读了Directory.CreateDirectory,它会说&#39;无论指定路径上的目录是否已经存在,都会返回此对象。&#39;这意味着您不会检测在检查存在和实际创建之间创建的文件夹。

我喜欢@DanielTrebbien建议的CreateDirectoryTransacted(),但不推荐使用此功能。

我看到的唯一解决方案是使用c api并拨打&#39; CreateDirectory&#39;如果你真的需要确保覆盖整个竞争条件,那么如果文件夹存在则会出错。 这将导致类似这样的事情:

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