Windows временное поведение файлов - они удалены системой?

Используя ответ Фелипе Леусина в течение многих лет, после недавнего обновления основных библиотек и Json.Net, я столкнулся с System.MissingMethodException: SupportedMediaTypes. Решение в моем случае, надеюсь, полезно для других, испытывающих такое же неожиданное исключение, заключается в установке System.Net.Http. NuGet, по-видимому, удаляет его при некоторых обстоятельствах. После ручной установки проблема была решена.

40
задан Bogdan Gavril MSFT 28 November 2008 в 01:40
поделиться

7 ответов

Короткий ответ: они не становятся удаленными.

длинный ответ: управляемое 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.

я нашел большую статью названной "Те противные временные файлы" (Заархивированный октябрь 2007), который начинает с основ и касается некоторых менее очевидных проблем обработки временных файлов, как:

  • , Как удостовериться, файл удален (даже если сбои приложения! подсказка: 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

}
42
ответ дан Community 5 August 2019 в 05:56
поделиться

На основе мартовских файлов в моем %tmp % я сказал бы нет.

Ре, почему их называют временными - потому что это - их ожидаемое использование. Они не системные файлы; они не файлы приложения, и они не пользовательские документы..., они существуют только, чтобы позволить приложению делать временную обработку (возможно, на больших объемах данных), или часто передавать данные через 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);
    }
}
8
ответ дан Marc Gravell 5 August 2019 в 05:56
поделиться

Существует FileOptions. Опция DeleteOnClose, которая могла бы сделать то, что Вы хотите.

Вот ссылка на страница MSDN .

5
ответ дан paul 5 August 2019 в 05:56
поделиться

Нет, это не верно. В основном Ваше приложение ответственно за чистку его собственной путаницы. Если Вы не сделаете, временные файлы будут накапливаться со временем.

1
ответ дан Mihai Limbășan 5 August 2019 в 05:56
поделиться

Нет, это находится в ответственности программного обеспечения (чтение: разработчик), который создает временный файл для избавления от него.

Взглянули в Вашей собственной временной папке, чтобы видеть, как хорошо, который работает;-)

0
ответ дан Treb 5 August 2019 в 05:56
поделиться

Их называют временными, потому что в большинстве случаев, пользователь может предположить, что она может безопасно разгрести бардак во временных директорах В противном случае в целом, эти файлы заблокированы так или иначе.

В целом, эти файлы должны быть недолгими: создайте их, используйте их для любой потребности, Вы имеете, удаляете их на месте. В худшем удалите их при выходе из приложения.

Когда-то, Вы не можете, например, менеджер архива или VCS, позволяющий смотреть на файл с редактором (или различное средство просмотра, и т.д.), но закрытый перед редактором (или не способные контролировать порожденный процесс...).

0
ответ дан PhiLho 5 August 2019 в 05:56
поделиться

Я много раз читал в Интернете, что люди не хотят использовать 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 возвращается с точкой.

для решения проблемы вы можете создать имя файла на основе 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 возвращается с точкой.

для решения проблемы вы можете создать имя файла на основе 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 возвращается с точкой.

-2
ответ дан 27 November 2019 в 01:49
поделиться
Другие вопросы по тегам:

Похожие вопросы: