2008-11-27 10 views
35

Korzystanie .NET Framework masz możliwość tworzenia plików tymczasowych zZachowanie plików tymczasowych systemu Windows - czy są one usuwane przez system?

Path.GetTempFileName(); 

MSDN nie powiedzieć nam, co się dzieje z plików tymczasowych. Pamiętam, że czytałem gdzieś, że są one usuwane przez system operacyjny, gdy pojawi się restart. Czy to prawda?

Jeśli pliki nie są usuwane przez system operacyjny, dlaczego są nazywane tymczasowe? Są normalnymi plikami w normalnym katalogu.

Odpowiedz

41

Krótka odpowiedź: nie zostaną usunięte.

Długa odpowiedź: zarządzanego Path.GetTempFileName() metoda zwraca rodzimą Win32API GetTempFileName() metody tak:

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

Dokumentacja dla rodzimych państw metoda:

Tymczasowe pliki, których nazwy mają utworzone przez tę funkcję nie są automatycznie usuwane. Aby usunąć te pliki, wywołaj DeleteFile.

Znalazłem ciekawy artykuł o nazwie "Those pesky temp files" (Archived Oct. 2007), który zaczyna się od podstaw i dotyka kilka mniej oczywistych problemów z obsługi plików tymczasowych, takich jak:

  • Jak upewnić się, że plik jest usunięte (nawet jeśli awarie aplikacji wskazówka: FileOption.DeleteOnClose i niech ofertę jądra z nim)
  • Jak uzyskać prawidłową politykę buforowania pliku, w celu zwiększenia wydajności (wskazówka: FileAttributes.Temporary)
  • Jak upewnić się, że zawartość s pliku czuć się bezpiecznie, ponieważ:
    • nazwa pliku jest nawet bardziej przewidywalny z zarządzanym metodą niż z niekontrolowana jednej
    • pliku temp jest tworzony, następnie zamknięte, wtedy masz ścieżkę do to (tylko po to, aby otworzyć go ponownie), pozostawiając w ten sposób małe okno dla złośliwego kodu/użytkowników do przejęcia pliku.

C# kod z artykułu:

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

Nie, to nieprawda. Zasadniczo twoja aplikacja jest odpowiedzialna za sprzątanie własnego bałaganu. Jeśli tego nie zrobisz, pliki tymczasowe będą się gromadzić z czasem.

8

Na podstawie plików marzec w moim% tmp%, powiedziałbym, że nie.

To dlatego są one nazywane tymczasowymi - ponieważ takie są ich oczekiwane użycie. Nie są to pliki systemowe; nie są to pliki aplikacji i nie są dokumentami użytkownika ... istnieją tylko po to, aby aplikacja mogła tymczasowo przetwarzać (być może przy dużych ilościach danych) lub często przekazywać dane za pośrednictwem IPC do innego procesu. W związku z tym są one naprawdę tymczasowe.

Powinieneś dążyć do usunięcia utworzonych przez ciebie plików tymczasowych, śmiertelnych "zabić" itp. Często używam „za pomocą” dla tego - utworzyć klasy otoki - tj

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

Mam tu odłamywać, ale nie powinno się "File.Delete" zostać przeniesione przed i przed sprawdzeniem zerowym, a sam zerowy czek jest zastąpiony sprawdzeniem "disposing"? 'try {File.Delete (ścieżka); } catch {} if (disposing) {path = null; } 'Oczywiście nie zmienia to wyniku w żaden sposób. – Stijn

0

Nie, to leży w gestii oprogramowania (czytaj: dewelopera), który tworzy plik tymczasowy do rozporządzania nim.

Sprawdźcie we własnym folderze temp, aby zobaczyć, jak dobrze, że działa ;-)

5

Jest FileOptions.DeleteOnClose opcja, która może robić, co chcesz.

Tutaj znajduje się link do strony .

0

Nazywane są tymczasowe, ponieważ w większości przypadków użytkownik może założyć, że może bezpiecznie usunąć bałagan w katalogach tymczasowych ... Jeśli nie, ogólnie te pliki są i tak zablokowane.

Ogólnie rzecz biorąc, pliki te powinny być krótkotrwałe: tworzyć je, wykorzystywać je do potrzebnych potrzeb, usuwać na miejscu. Co gorsza, usuń je przy wychodzeniu z aplikacji.

Kiedyś nie możesz np. menedżer archiwum lub VCS umożliwiający przeglądanie pliku za pomocą edytora (lub przeglądarki diff, itp.), ale zamykany przed edytorem (lub nie może monitorować procesu odradzania ...).

-2

Czytałem w internecie, wiele razy, że ludzie nie chcą korzystać Path.GetTempFileName bo mówią, to może powrócić już istniejący plik, aby rozwiązać problem, możesz utworzyć nazwę pliku na podstawie identyfikatora GUID.

Ta funkcja rozwiązuje ten problem: Powoduje iterację do momentu znalezienia nieistniejącej nazwy pliku z określonym rozszerzeniem.

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

Uwaga: używam argumentów extensionWithDot ponieważ System.IO.Path.GetExtension powraca z kropką.

+0

Sprawdź proszę swój angielski. –

+1

Dla każdego, kto spotka się z tym w przyszłości, ta odpowiedź rozwiąże nieistniejący problem - "GetTempFileName" gwarantuje zwrócenie unikalnie nazwanego pliku. Nie musisz mi wierzyć na słowo, jest to bardzo jasne w dokumentacji. Również pozostawia 0-bajtowe pliki tymczasowe w katalogu tymczasowym, które są złe. – caesay

Powiązane problemy