C# で一時ファイルを自動的に削除するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/400140

  •  03-07-2019
  •  | 
  •  

質問

アプリケーションが終了またはクラッシュした場合に一時ファイルを確実に削除する良い方法は何ですか?理想的には、一時ファイルを取得して使用し、その後は忘れたいと考えています。

現在、一時ファイルのリストを保持し、Application.ApplicationExit でトリガーされるイベントハンドラーを使用してそれらを削除しています。

もっと良い方法はありますか?

役に立ちましたか?

解決

プロセスが途中で終了した場合は何も保証されませんが、「 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 が破棄またはガベージコレクションされると、ファイルは削除されます(可能な場合)。もちろん、これを好きなように厳密なスコープで使用することも、どこかのコレクションで使用することもできます。

他のヒント

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

P / Invoke CreateFile そして、 FILE_FLAG_DELETE_ON_CLOSE フラグを渡します。これは、すべてのハンドルが閉じられると、ファイルを削除するようWindowsに指示します。参照: Win32 CreateFile docs

.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.");
    }

私は主にC#プログラマーではありませんが、C ++では RAII を使用しますこのため。いくつかの C#でRAIIのような動作をオンラインで使用することのヒントですが、ほとんどはファイナライザーを使用しているようです—確定的ではありません。

一時ファイルを作成するWindows SDK関数はいくつかあると思いますが、プログラムの終了時にそれらが自動的に削除されるかどうかはわかりません。 GetTempPath 関数がありますが、ファイルはログアウトまたは再起動するときにのみ削除されます、IIRC。

PS C#デストラクタドキュメントでは、そこにリソースをリリースできることを示しています。私は少し奇妙に感じます。その場合、デストラクタで一時ファイルを削除するだけで済みますが、これも完全に確定的ではない可能性があります。

あなたが責任を持ちたいと思うのは良いことですが、ファイルが大きくない場合(> 50MB)、tempディレクトリに残しておくことで(MSを含む)全員と一致します。ディスク容量が豊富です。

cslが投稿したように、GetTempPathが道です。スペースが不足しているユーザーはディスククリーンアップを実行でき、ファイルは(他のすべてのユーザーと共に)クリーンアップされます。

より信頼性の高いソリューションを使用しています:

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

アプリケーションの開始時。

起動時にスレッドを起動して、「あるべきではない」ときに存在するファイルを削除できます。クラッシュから回復します。

Windowsフォームアプリケーションを構築している場合、次のコードを使用できます。

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        File.Delete("temp.data");
    }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top