2008-11-27 36 views
35

Sử dụng khung .net bạn có tùy chọn để tạo ra các file tạm thời vớiHành vi tệp tạm thời của Windows - chúng có bị hệ thống xóa không?

Path.GetTempFileName(); 

MSDN không cho chúng tôi biết những gì xảy ra với tệp tạm thời. Tôi nhớ đọc ở đâu đó rằng họ bị xóa bởi hệ điều hành khi nó được khởi động lại. Điều này có đúng không?

Nếu các tệp không bị hệ điều hành xóa, tại sao chúng được gọi là tạm thời? Chúng là các tệp bình thường trong một thư mục bình thường.

Trả lời

41

Câu trả lời ngắn gọn: chúng không bị xóa.

Câu trả lời dài: Các quản lý Path.GetTempFileName() phương pháp gọi là có nguồn gốc phương pháp Win32API GetTempFileName(), như thế này:

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

Các tài liệu cho các tiểu bang phương pháp bản địa:

file tạm thời có tên có được tạo bởi chức năng này không bị xóa tự động. Để xóa các tệp này, hãy gọi DeleteFile.

Tôi đã tìm thấy một bài viết tuyệt vời gọi là "Those pesky temp files" (lưu trữ tháng 10 năm 2007) bắt đầu từ căn bản và chạm vào một số vấn đề chưa rõ ràng về xử lý tập tin tạm thời, như:

  • Làm thế nào để chắc chắn rằng các tập tin là xóa (ngay cả khi treo ứng dụng gợi ý: FileOption.DeleteOnClose và để cho các thỏa thuận hạt nhân với nó)
  • làm thế nào để có được những chính sách bộ nhớ đệm chính xác cho các tập tin, để cải thiện hiệu suất (gợi ý: FileAttributes.Temporary)
  • làm thế nào để đảm bảo nội dung s của file ở lại an toàn, bởi vì:
    • tên tập tin thậm chí còn dự đoán nhiều hơn với phương pháp quản lý hơn với không được quản lý một
    • tập tin tạm thời được tạo ra, sau đó đóng, sau đó bạn sẽ có được đường dẫn đến nó (chỉ để mở lại), do đó để lại một cửa sổ nhỏ cơ hội cho mã độc/người dùng xâm nhập tệp.

C# Mã từ bài viết:

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

Không, điều này không đúng. Về cơ bản, ứng dụng của bạn có trách nhiệm dọn dẹp đống lộn xộn của riêng mình. Nếu không, các tệp tạm thời sẽ tích luỹ theo thời gian.

8

Dựa trên các tệp tháng 3 trong% tmp% của tôi, tôi muốn nói là không.

Lý do tại sao chúng được gọi là tạm thời - vì đó là cách sử dụng dự kiến ​​của chúng. Chúng không phải là các tệp hệ thống; chúng không phải là các tệp ứng dụng và chúng không phải là tài liệu người dùng ... chúng chỉ tồn tại để cho phép ứng dụng thực hiện xử lý tạm thời (có thể trên lượng lớn dữ liệu) hoặc thường xuyên chuyển dữ liệu qua IPC sang một quy trình khác. Do đó chúng thực sự là tạm thời.

Bạn nên cố gắng xóa mọi tệp tạm thời mà bạn tạo, gây tử vong "giết" v.v. không chịu được. Tôi thường sử dụng "sử dụng" cho điều này - tôi tạo ra một lớp wrapper - ví dụ:

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

Tôi đang nitpicking ở đây, nhưng không nên 'File.Delete' được di chuyển ra khỏi và trước khi kiểm tra null, và kiểm tra null chính nó được thay thế bằng một kiểm tra' disposing'? 'try {File.Delete (đường dẫn); } catch {} nếu (vứt bỏ) {path = null; } 'Không phải là nó thay đổi kết quả theo bất kỳ cách nào, tất nhiên. – Stijn

0

Không, nó nằm trong trách nhiệm của phần mềm (đọc: các nhà phát triển) mà tạo ra một tập tin tạm thời để xử lý nó.

Có một cái nhìn trong thư mục tạm của riêng bạn để xem như thế nào mà làm việc ;-)

5

Có một FileOptions.DeleteOnClose tùy chọn mà có thể làm những gì bạn muốn.

Đây là liên kết đến trang MSDN.

0

Chúng được gọi là tạm thời vì trong hầu hết các trường hợp, người dùng có thể giả định rằng mình có thể dọn sạch một cách an toàn các mớ hỗn độn trong các thư mục tạm thời ... Nếu không, nói chung, các tệp này bị khóa.

Nói chung, các tệp này phải ngắn ngủi: tạo chúng, sử dụng chúng cho bất kỳ nhu cầu nào bạn có, xóa chúng ngay tại chỗ. Tệ hơn, hãy xóa chúng khi thoát khỏi ứng dụng.

Thỉnh thoảng, bạn không thể, ví dụ: một trình quản lý lưu trữ hoặc VCS cho phép xem một tệp có trình chỉnh sửa (hoặc trình xem khác, v.v.), nhưng đã đóng trước trình chỉnh sửa (hoặc không thể theo dõi quá trình sinh sản ...).

-2

Tôi đã đọc trên internet rất nhiều lần so với người không muốn sử dụng Path.GetTempFileName vì họ nói nó có thể trở lại một đã tồn tại tập tin, để giải quyết vấn đề bạn có thể làm cho một tên tập tin dựa trên một GUID.

Chức năng này giải quyết vấn đề đó: Lặp lại cho đến khi tìm thấy tên tệp không tồn tại với phần mở rộng cụ thể.

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

Lưu ý: Tôi sử dụng lập luận extensionWithDot vì System.IO.Path.GetExtension trả về với dấu chấm.

+0

Xem lại tiếng anh của bạn. –

+1

Đối với bất cứ ai đến đây trong tương lai, câu trả lời này giải quyết một vấn đề không tồn tại - 'GetTempFileName' được đảm bảo trả về một tệp có tên duy nhất. Bạn không cần phải dùng từ ngữ của tôi cho nó, nó là rất rõ ràng về điều này trong tài liệu. Ngoài ra, điều này lá 0-byte temp tập tin trong thư mục tạm thời đó là xấu. – caesay

Các vấn đề liên quan