Как автоматически удалить временные файлы в c #? - PullRequest
52 голосов
/ 30 декабря 2008

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

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

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

Ответы [ 9 ]

71 голосов
/ 30 декабря 2008

Ничто не гарантируется, если процесс завершен преждевременно, однако я использую "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 удаляется или собирается мусор, файл удаляется (если это возможно). Очевидно, вы могли бы использовать его настолько узко, как вам нравится, или где-нибудь в коллекции.

54 голосов
/ 20 августа 2014

Рассмотрите возможность использования флага 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
18 голосов
/ 30 декабря 2008

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

4 голосов
/ 04 апреля 2014

Я бы использовал класс .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's 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.");
    }
3 голосов
/ 30 декабря 2008

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

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

3 голосов
/ 30 декабря 2008

Я не программист C #, но в C ++ я бы использовал RAII для этого. Есть некоторые подсказки по использованию RAII-подобного поведения в C # онлайн, но большинство, похоже, используют финализатор & mdash; который не является детерминированным.

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

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

2 голосов
/ 19 ноября 2014

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

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

при запуске приложения.

0 голосов
/ 15 июля 2015

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

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }
0 голосов
/ 30 декабря 2008

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

...