アプリケーションが終了またはクラッシュした場合に一時ファイルを確実に削除するにはどうすればよいですか? 理想的には、一時ファイルを取得して使用し、その後は忘れたいと考えています。
現在、一時ファイルのリストを保持し、Application.ApplicationExit でトリガーされる EventHandler を使用してそれらを削除しています。
より良い方法はありますか?
アプリケーションが終了またはクラッシュした場合に一時ファイルを確実に削除するにはどうすればよいですか? 理想的には、一時ファイルを取得して使用し、その後は忘れたいと考えています。
現在、一時ファイルのリストを保持し、Application.ApplicationExit でトリガーされる EventHandler を使用してそれらを削除しています。
より良い方法はありますか?
プロセスが途中で強制終了された場合は何も保証されませんが、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/InvokeCreateFile
FILE_FLAG_DELETE_ON_CLOSE
してフラグを渡すことができます。これにより、すべてのハンドルが閉じられたらファイルを削除するように Windows に指示されます。参照: Win32CreateFile
ドキュメント.
組み込みの .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.");
}
私はより信頼性の高いソリューションを使用しています:
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();
アプリケーションの開始時。
私は主にC#プログラマーではありませんが、C++ではこれにRAIIを使用します。C#オンラインでRAIIのような動作を使用するためのヒントがいくつかありますが、ほとんどの場合、ファイナライザーを使用しているようです。これは決定論的ではありません。
一時ファイルを作成するWindowsSDKの機能はいくつかあると思いますが、プログラムの終了時に自動的に削除されるかどうかはわかりません。GetTempPath関数がありますが、そこにあるファイルは、ログアウトまたは再起動したときにのみ削除されます、IIRC。
PS C#デストラクタのドキュメントには、リソースをリリースできると記載されていますが、少し奇妙だと思います。その場合、デストラクタで一時ファイルを削除するだけで済みますが、これも完全に決定論的ではない可能性があります。
クラッシュから回復する必要がない場合に存在するファイルを削除するスレッドを起動時に起動できます。