Подтвердить что ты не робот

Как автоматически удалить tempfiles в С#?

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

Сейчас я сохраняю список своих tempfiles и удаляю их с помощью обработчика событий, запускающего Application.ApplicationExit.

Есть ли лучший способ?

4b9b3361

Ответ 1

Ничего не гарантируется, если процесс убит досрочно, однако я использую "using", чтобы сделать это.

using System;
using System.IO;
sealed class TempFile : IDisposable
{
    string path;
    public TempFile() : this(System.IO.Path.GetTempFileName()) { }

    public TempFile(string path)
    {
        if (string.IsNullOrEmpty(path)) throw new ArgumentNullException("path");
        this.path = path;
    }
    public string Path
    {
        get
        {
            if (path == null) throw new ObjectDisposedException(GetType().Name);
            return path;
        }
    }
    ~TempFile() { Dispose(false); }
    public void Dispose() { Dispose(true); }
    private void Dispose(bool disposing)
    {
        if (disposing)
        {
            GC.SuppressFinalize(this);                
        }
        if (path != null)
        {
            try { File.Delete(path); }
            catch { } // best effort
            path = null;
        }
    }
}
static class Program
{
    static void Main()
    {
        string path;
        using (var tmp = new TempFile())
        {
            path = tmp.Path;
            Console.WriteLine(File.Exists(path));
        }
        Console.WriteLine(File.Exists(path));
    }
}

Теперь, когда TempFile удаляется или собирается мусор, файл удаляется (если это возможно). Вы, очевидно, могли бы использовать это как сильно ограниченное, как вам нравится, или в какой-то коллекции.

Ответ 2

Рассмотрим использование флажка FileOptions.DeleteOnClose:

using (FileStream fs = new FileStream(Path.GetTempFileName(),
       FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None,
       4096, FileOptions.RandomAccess | FileOptions.DeleteOnClose))
{
    // temp file exists
}

// temp file is gone

Ответ 3

Вы можете P/Invoke CreateFile и передать флаг FILE_FLAG_DELETE_ON_CLOSE. Это говорит Windows, чтобы удалить файл после закрытия всех дескрипторов. См. Также: Win32 CreateFile docs.

Ответ 4

Я бы использовал класс .NET TempFileCollection, поскольку он встроен, доступен в старых версиях .NET и реализует интерфейс IDisposable и, таким образом, очищает после себя, если используется, например. в сочетании с ключевым словом "using".

Вот пример, который извлекает текст из встроенного ресурса (добавляется через страницы свойств проекта → вкладка "Ресурсы", как описано здесь: Как вставить текстовый файл в сборку .NET?, затем установите значение "EmbeddedResource" во встроенные параметры свойств файла).

    // Extracts the contents of the embedded file, writes them to a temp file, executes it, and cleans up automatically on exit.
    private void ExtractAndRunMyScript()
    {
        string vbsFilePath;

        // By default, TempFileCollection cleans up after itself.
        using (var tempFiles = new System.CodeDom.Compiler.TempFileCollection())
        {
            vbsFilePath= tempFiles.AddExtension("vbs");

            // Using IntelliSense will display the name, but it the file name
            // minus its extension.
            System.IO.File.WriteAllText(vbsFilePath, global::Instrumentation.Properties.Resources.MyEmbeddedFileNameWithoutExtension);

            RunMyScript(vbsFilePath);
        }

        System.Diagnostics.Debug.Assert(!File.Exists(vbsFilePath), @"Temp file """ + vbsFilePath+ @""" has not been deleted.");
    }

Ответ 5

Я не программист на С#, но в С++ я бы использовал RAII. Есть несколько подсказки по использованию поведения, подобного RAII, на С# в Интернете, но большинство из них, похоже, использует finalizer — который не является детерминированным.

Я думаю, что есть некоторые функции Windows SDK для создания временных файлов, но не знаю, автоматически ли они удаляются при завершении программы. Существует функция GetTempPath, но файлы там удаляются только при выходе из системы или перезапуске, IIRC.

P.S. документация деструктора С# говорит, что вы можете и должны выделять там ресурсы, которые я нахожу немного странными. Если это так, вы можете просто удалить временный файл в деструкторе, но опять же, это может быть не полностью детерминированным.

Ответ 6

Приятно видеть, что вы хотите быть ответственным, но если файлы не огромны ( > 50 Мбайт), вы бы соответствовали всем (включая MS), оставляя их в каталоге temp. Дисковое пространство в изобилии.

Как указано csl, GetTempPath - это путь. Пользователи, у которых хватает места, смогут запустить очистку диска, и ваши файлы (вместе со всеми остальными) будут очищены.

Ответ 7

Я использую более надежное решение:

using System.IO;
using System.Reflection;

namespace Konard.Helpers
{
    public static partial class TemporaryFiles
    {
        private const string UserFilesListFilenamePrefix = ".used-temporary-files.txt";
        static private readonly object UsedFilesListLock = new object();

        private static string GetUsedFilesListFilename()
        {
            return Assembly.GetEntryAssembly().Location + UserFilesListFilenamePrefix;
        }

        private static void AddToUsedFilesList(string filename)
        {
            lock (UsedFilesListLock)
            {
                using (var writer = File.AppendText(GetUsedFilesListFilename()))
                    writer.WriteLine(filename);
            }
        }

        public static string UseNew()
        {
            var filename = Path.GetTempFileName();
            AddToUsedFilesList(filename);
            return filename;
        }

        public static void DeleteAllPreviouslyUsed()
        {
            lock (UsedFilesListLock)
            {
                var usedFilesListFilename = GetUsedFilesListFilename();

                if (!File.Exists(usedFilesListFilename))
                    return;

                using (var listFile = File.Open(usedFilesListFilename, FileMode.Open))
                {
                    using (var reader = new StreamReader(listFile))
                    {
                        string tempFileToDelete;
                        while ((tempFileToDelete = reader.ReadLine()) != null)
                        {
                            if (File.Exists(tempFileToDelete))
                                File.Delete(tempFileToDelete);
                        }
                    }
                }

                // Clean up
                using (File.Open(usedFilesListFilename, FileMode.Truncate)) { }
            }
        }
    }
}

Каждый раз, когда вам требуется временное использование файла:

var tempFile = TemporaryFiles.UseNew();

Чтобы убедиться, что все временные файлы удаляются после закрытия приложения или сбоев, поставьте

TemporaryFiles.DeleteAllPreviouslyUsed();

в начале приложения.

Ответ 8

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

Ответ 9

Если вы создаете приложение Windows Forms, вы можете использовать этот код:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }