2008-11-27 58 views
35

使用.NET Framework,你必须创建临时文件与Windows临时文件行为 - 它们是否被系统删除?

Path.GetTempFileName(); 

的MSDN没有告诉我们发生了什么临时文件的选项。我记得在某个地方,当它重新启动时,它们被操作系统删除。这是真的?

如果文件没有被操作系统删除,为什么他们被称为临时?它们是普通目录中的普通文件。

回答

41

简短的回答:他们不会被删除。

长的答案: 托管Path.GetTempFileName()方法调用本机的Win32API GetTempFileName()方法,像这样:

//actual .NET 2.0 decompiled code 
// .NET Reflector rocks for looking at plumbing 
public static string GetTempFileName() 
{ 
    string tempPath = GetTempPath(); 
    new FileIOPermission(FileIOPermissionAccess.Write, tempPath).Demand(); 
    StringBuilder tmpFileName = new StringBuilder(260); 
    if (Win32Native.GetTempFileName(tempPath, "tmp", 0, tmpFileName) == 0) 
    { 
     __Error.WinIOError(); 
    } 
    return tmpFileName.ToString(); 
} 

的本地方法状态的文档:

临时文件的名字有由此功能创建的内容不会自动删除。要删除这些文件,请调用DeleteFile。

我已经找到了一个堪称伟大的文章"Those pesky temp files"(归档2007年10月),从基础开始,触动的处理临时文件,像一些不太明显的问题:

  • 如何确保该文件删除(即使该应用程序崩溃提示:FileOption.DeleteOnClose,让内核处理它)
  • 如何得到正确的缓存策略文件,以提高性能(提示:FileAttributes.Temporary
  • 如何确保内容该文件第呆在安全的,这是因为:
    • 文件名更是可预测的比与非托管一个
    • 临时文件的管理方法被创建,然后关闭,那么你得到的路径它(只是再次打开它),从而为恶意代码/用户劫持文件留下一个小小的机会窗口。从文章

C#代码:

using System; 
using System.IO; 
using System.Security.Permissions; 
using System.Security.Principal; 
using System.Security.AccessControl; 

public static class PathUtility 
{ 
    private const int defaultBufferSize = 0x1000; // 4KB 

#region GetSecureDeleteOnCloseTempFileStream 

    /// <summary> 
    /// Creates a unique, randomly named, secure, zero-byte temporary file on disk, which is automatically deleted when it is no longer in use. Returns the opened file stream. 
    /// </summary> 
    /// <remarks> 
    /// <para>The generated file name is a cryptographically strong, random string. The file name is guaranteed to be unique to the system's temporary folder.</para> 
    /// <para>The <see cref="GetSecureDeleteOnCloseTempFileStream"/> method will raise an <see cref="IOException"/> if no unique temporary file name is available. Although this is possible, it is highly improbable. To resolve this error, delete all uneeded temporary files.</para> 
    /// <para>The file is created as a zero-byte file in the system's temporary folder.</para> 
    /// <para>The file owner is set to the current user. The file security permissions grant full control to the current user only.</para> 
    /// <para>The file sharing is set to none.</para> 
    /// <para>The file is marked as a temporary file. File systems avoid writing data back to mass storage if sufficient cache memory is available, because an application deletes a temporary file after a handle is closed. In that case, the system can entirely avoid writing the data. Otherwise, the data is written after the handle is closed.</para> 
    /// <para>The system deletes the file immediately after it is closed or the <see cref="FileStream"/> is finalized.</para> 
    /// </remarks> 
    /// <returns>The opened <see cref="FileStream"/> object.</returns> 
    public static FileStream GetSecureDeleteOnCloseTempFileStream() 
    {  
     return GetSecureDeleteOnCloseTempFileStream(defaultBufferSize, FileOptions.DeleteOnClose);  
    } 

    /// <summary> 
    /// Creates a unique, randomly named, secure, zero-byte temporary file on disk, which is automatically deleted when it is no longer in use. Returns the opened file stream with the specified buffer size. 
    /// </summary> 
    /// <remarks> 
    /// <para>The generated file name is a cryptographically strong, random string. The file name is guaranteed to be unique to the system's temporary folder.</para> 
    /// <para>The <see cref="GetSecureDeleteOnCloseTempFileStream"/> method will raise an <see cref="IOException"/> if no unique temporary file name is available. Although this is possible, it is highly improbable. To resolve this error, delete all uneeded temporary files.</para> 
    /// <para>The file is created as a zero-byte file in the system's temporary folder.</para> 
    /// <para>The file owner is set to the current user. The file security permissions grant full control to the current user only.</para> 
    /// <para>The file sharing is set to none.</para> 
    /// <para>The file is marked as a temporary file. File systems avoid writing data back to mass storage if sufficient cache memory is available, because an application deletes a temporary file after a handle is closed. In that case, the system can entirely avoid writing the data. Otherwise, the data is written after the handle is closed.</para> 
    /// <para>The system deletes the file immediately after it is closed or the <see cref="FileStream"/> is finalized.</para> 
    /// </remarks> 
    /// <param name="bufferSize">A positive <see cref="Int32"/> value greater than 0 indicating the buffer size.</param> 
    /// <returns>The opened <see cref="FileStream"/> object.</returns> 
    public static FileStream GetSecureDeleteOnCloseTempFileStream(int bufferSize) 
    { 
     return GetSecureDeleteOnCloseTempFileStream(bufferSize, FileOptions.DeleteOnClose); 
    } 

    /// <summary> 
    /// Creates a unique, randomly named, secure, zero-byte temporary file on disk, which is automatically deleted when it is no longer in use. Returns the opened file stream with the specified buffer size and file options. 
    /// </summary> 
    /// <remarks> 
    /// <para>The generated file name is a cryptographically strong, random string. The file name is guaranteed to be unique to the system's temporary folder.</para> 
    /// <para>The <see cref="GetSecureDeleteOnCloseTempFileStream"/> method will raise an <see cref="IOException"/> if no unique temporary file name is available. Although this is possible, it is highly improbable. To resolve this error, delete all uneeded temporary files.</para> 
    /// <para>The file is created as a zero-byte file in the system's temporary folder.</para> 
    /// <para>The file owner is set to the current user. The file security permissions grant full control to the current user only.</para> 
    /// <para>The file sharing is set to none.</para> 
    /// <para>The file is marked as a temporary file. File systems avoid writing data back to mass storage if sufficient cache memory is available, because an application deletes a temporary file after a handle is closed. In that case, the system can entirely avoid writing the data. Otherwise, the data is written after the handle is closed.</para> 
    /// <para>The system deletes the file immediately after it is closed or the <see cref="FileStream"/> is finalized.</para> 
    /// <para>Use the <paramref name="options"/> parameter to specify additional file options. You can specify <see cref="FileOptions.Encrypted"/> to encrypt the file contents using the current user account. Specify <see cref="FileOptions.Asynchronous"/> to enable overlapped I/O when using asynchronous reads and writes.</para> 
    /// </remarks> 
    /// <param name="bufferSize">A positive <see cref="Int32"/> value greater than 0 indicating the buffer size.</param> 
    /// <param name="options">A <see cref="FileOptions"/> value that specifies additional file options.</param> 
    /// <returns>The opened <see cref="FileStream"/> object.</returns> 
    public static FileStream GetSecureDeleteOnCloseTempFileStream(int bufferSize, FileOptions options) 
    {  
     FileStream fs = GetSecureFileStream(Path.GetTempPath(), bufferSize, options | FileOptions.DeleteOnClose); 

     File.SetAttributes(fs.Name, File.GetAttributes(fs.Name) | FileAttributes.Temporary); 

     return fs;  
    } 

#endregion 

#region GetSecureTempFileStream 

    public static FileStream GetSecureTempFileStream() 
    {  
     return GetSecureTempFileStream(defaultBufferSize, FileOptions.None);  
    } 

    public static FileStream GetSecureTempFileStream(int bufferSize) 
    { 
     return GetSecureTempFileStream(bufferSize, FileOptions.None); 
    } 

    public static FileStream GetSecureTempFileStream(int bufferSize, FileOptions options) 
    { 
     FileStream fs = GetSecureFileStream(Path.GetTempPath(), bufferSize, options); 

     File.SetAttributes(fs.Name, File.GetAttributes(fs.Name) | FileAttributes.NotContentIndexed | FileAttributes.Temporary); 

     return fs; 
    } 

    #endregion 

#region GetSecureTempFileName 

    public static string GetSecureTempFileName() 
    {  
     return GetSecureTempFileName(false);  
    } 

    public static string GetSecureTempFileName(bool encrypted) 
    {  
     using (FileStream fs = GetSecureFileStream(Path.GetTempPath(), defaultBufferSize, encrypted ? FileOptions.Encrypted : FileOptions.None)) 
     {  
      File.SetAttributes(fs.Name, File.GetAttributes(fs.Name) | FileAttributes.NotContentIndexed | FileAttributes.Temporary); 

      return fs.Name;  
     } 

    } 

#endregion 

#region GetSecureFileName 

    public static string GetSecureFileName(string path) 
    {  
     return GetSecureFileName(path, false);  
    } 

    public static string GetSecureFileName(string path, bool encrypted) 
    {  
     using (FileStream fs = GetSecureFileStream(path, defaultBufferSize, encrypted ? FileOptions.Encrypted : FileOptions.None)) 
     {  
      return fs.Name;  
     }  
    } 

#endregion 

#region GetSecureFileStream 

    public static FileStream GetSecureFileStream(string path) 
    {  
     return GetSecureFileStream(path, defaultBufferSize, FileOptions.None);  
    } 

    public static FileStream GetSecureFileStream(string path, int bufferSize) 
    { 
     return GetSecureFileStream(path, bufferSize, FileOptions.None); 
    } 

    public static FileStream GetSecureFileStream(string path, int bufferSize, FileOptions options) 
    {  
     if (path == null) 
      throw new ArgumentNullException("path"); 

     if (bufferSize <= 0) 
      throw new ArgumentOutOfRangeException("bufferSize"); 

     if ((options & ~(FileOptions.Asynchronous | FileOptions.DeleteOnClose | FileOptions.Encrypted | FileOptions.RandomAccess | FileOptions.SequentialScan | FileOptions.WriteThrough)) != FileOptions.None) 
      throw new ArgumentOutOfRangeException("options"); 

     new FileIOPermission(FileIOPermissionAccess.Write, path).Demand(); 

     SecurityIdentifier user = WindowsIdentity.GetCurrent().User; 

     FileSecurity fileSecurity = new FileSecurity(); 

     fileSecurity.AddAccessRule(new FileSystemAccessRule(user, FileSystemRights.FullControl, AccessControlType.Allow)); 

     fileSecurity.SetAccessRuleProtection(true, false); 

     fileSecurity.SetOwner(user); 

     // Attempt to create a unique file three times before giving up. 
     // It is highly improbable that there will ever be a name clash, 
     // therefore we do not check to see if the file first exists. 

     for (int attempt = 0; attempt < 3; attempt++) 
     {  
      try 
      {  
       return new FileStream(Path.Combine(path, Path.GetRandomFileName()), 
             FileMode.CreateNew, FileSystemRights.FullControl, 
             FileShare.None, bufferSize, options, fileSecurity); 
      } 

      catch (IOException) 
      { 
       if (attempt == 2) 
        throw; 
      } 

     } 

     // This code can never be reached. 
     // The compiler thinks otherwise. 
     throw new IOException(); 

    } 

#endregion 

} 
1

不,这是不正确的。基本上,你的应用程序负责清理自己的混乱。如果你不这样做,临时文件会随着时间而积累。

8

基于我的%tmp%中的March文件,我不会说。

为什么他们被称为临时 - 因为这是他们的预期用法。他们不是系统文件;它们不是应用程序文件,并且它们不是用户文档......它们仅用于允许应用程序执行临时处理(可能在大量数据上),或者经常通过IPC将数据传递到另一个进程。因此,他们确实是暂时的。

你应该旨在删除你创建的任何临时文件,致命的“杀死”等不能承受。我经常使用“使用”这个 - 我创建一个包装类 - 即

sealed class TempFile : IDisposable { // formatted for space 
    string path; 
    public string Path { 
     get { 
      if(path==null) throw new ObjectDisposedException(GetType().Name); 
      return path; 
     } 
    } 
    public TempFile() : this(System.IO.Path.GetTempFileName()) { } 

    public TempFile(string path) { 
     if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path"); 
     this.path = path; 
    } 

    private void Dispose(bool disposing) { 
     if (path != null) { 
      try { 
       File.Delete(path); 
      } catch { } // best endeavours... 
      path = null; 
     } 
    } 
    public void Dispose() { 
     GC.SuppressFinalize(this); 
     Dispose(true); 
    } 
    ~TempFile() { 
     Dispose(false); 
    } 
} 
+0

我很挑剔这里,但不应该`File.Delete`被移出和之前的空检查,并且空检查本身被替换为`disposing`检查? `尝试{File.Delete(path); } catch {} if(disposing){path = null;当然,它不是以任何方式改变结果。 – Stijn 2017-07-31 08:59:39

0

不,这在于软件的责任(阅读:开发商),创建一个临时文件来处理它。

有在自己的临时文件夹看看,看看如何好,工程;-)

5

有一个FileOptions.DeleteOnClose选项,可能会做你想要什么。

这里是链接到MSDN页面。

0

他们被称为临时的,因为在大多数情况下,用户可以假定她可以安全地清理临时区域中的垃圾......如果没有,一般来说,这些文件无论如何都是锁定的。

通常,这些文件应该是短暂的:创建它们,将它们用于任何需要的位置,然后当场删除它们。更糟的是,在退出应用程序时将其删除。

有时,你不能,例如。一个档案管理器或VCS允许用编辑器(或差异查看器等)查看文件,但在编辑器之前关闭(或不能监视产生的过程...)。

-2

我已经在互联网上读了很多次,人们不希望使用Path.GetTempFileName,因为他们说这可能会返回一个已经存在的文件,为了解决这个问题,你可以根据一个GUID做一个文件名。

这个函数解决了这个问题:迭代直到找到一个不存在的文件名和一个特定的扩展名。

VB.net

Public Shared Function GetTempFileName(ByVal extensionWithDot As String) As String 
    Dim tempFileName As String 
    Do 
     tempFileName = System.IO.Path.GetTempFileName 
     If extensionWithDot IsNot Nothing Then 
      tempFileName = tempFileName.Replace(System.IO.Path.GetExtension(tempFileName), extensionWithDot) 
     End If 
    Loop While System.IO.File.Exists(tempFileName) 
    Return tempFileName 
End Function 

C#:

public static string GetTempFileName(string extensionWithDot) 
{ 
    string tempFileName = null; 
    do { 
     tempFileName = System.IO.Path.GetTempFileName; 
     if (extensionWithDot != null) { 
      tempFileName = tempFileName.Replace(System.IO.Path.GetExtension(tempFileName), extensionWithDot); 
     } 
    } while (System.IO.File.Exists(tempFileName)); 
    return tempFileName; 
} 

注:我使用的参数extensionWithDot因为System.IO.Path.GetExtension与点返回。

+0

请检查您的英语。 – 2009-11-26 16:09:06

相关问题