67

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

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

より良い方法はありますか?

4

9 に答える 9

84

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

于 2008-12-30T14:30:42.117 に答える
72

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
于 2014-08-20T18:14:32.833 に答える
20

P/InvokeCreateFileFILE_FLAG_DELETE_ON_CLOSEしてフラグを渡すことができます。これにより、すべてのハンドルが閉じられたらファイルを削除するように Windows に指示されます。参照: Win32CreateFileドキュメント.

于 2008-12-30T14:45:40.120 に答える
7

組み込みの .NETTempFileCollectionクラスを使用し、古いバージョンの .NET で使用できます。インターフェイスを実装しているため、たとえばキーワード IDisposableと組み合わせて使用​​すると、それ自体がクリーンアップされます。"using"

埋め込みリソースからテキストを抽出する例を次に示します (プロジェクトのプロパティ ページ -> [リソース] タブを介して追加されます (ここで説明されているように: How to embed a text file in a .NET assembly?で説明されているよう"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.");
    }
于 2014-04-04T00:32:31.347 に答える
6

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

using System.IO;
using System.Reflection;
 
namespace 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();

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

于 2014-11-19T13:54:00.313 に答える
3

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

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

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

于 2008-12-30T12:46:43.557 に答える
3

責任を持って対処するのは良いことですが、ファイルが大きくない場合 (>50MB) は、すべてのユーザー (MS を含む) と同じように一時ディレクトリにファイルを残すことになります。ディスク容量は豊富です。

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

于 2008-12-30T13:10:38.487 に答える
0

クラッシュから回復する必要がない場合に存在するファイルを削除するスレッドを起動時に起動できます。

于 2008-12-30T16:54:22.683 に答える