トップ回答者
ファイルやフォルダの強制削除

質問
回答
-
他のOSと異なりWindowsの場合、ウィルス対策ソフトが稼働していることが多く、ファイルアクセスをすると対策ソフトが追跡して再オープンしてくるので、ファイル使用後の削除には(まだスキャン中なため)失敗しやすい印象です。
別のアプローチで、FileStreamクラスのコンストラクターにはFileOptionsを指定することができますが、この中にDeleteOnCloseがあります。これを指定するとファイルを閉じる際に自動的に削除されます。これはOSによる削除機能なので確実に消せるはずです。
- 回答としてマーク manabubu 2015年5月13日 1:55
-
強制的に削除する方法はおそらく無いです。
他のプロセスが重要な処理の最中にもしも削除ができてしまった場合、そのプロセスのクラッシュを引き起こすことになりますよね。
#fm -forceは知りませんが、Windowsのrmdir /Qではメッセージが出ないだけで失敗しますそれよりもユーザーが簡単にアクセスできる場所にはテンポラリを作らないという方法を取った方がいいと思います。
using System; using System.Reflection; using System.Runtime.InteropServices; using System.IO; class Program { static void Main(string[] args) { //IsolatedStorageという見つけにくい場所を使う var storage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForAssembly(); //IsolatedStrageのフルパスをリフレクションで取り出し var pi = storage.GetType().GetProperty("RootDirectory", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); string tempDir = System.IO.Path.Combine((string)pi.GetValue(storage, null), "tempDir"); var di = new System.IO.DirectoryInfo(tempDir); di.Create(); //隠し属性にして見つけにくくする di.Attributes |= System.IO.FileAttributes.Hidden; //一時フォルダをカレントにしてコマンドプロンプトを開く System.Diagnostics.ProcessStartInfo si = new System.Diagnostics.ProcessStartInfo("cmd"); si.WorkingDirectory = tempDir; System.Diagnostics.Process.Start(si); Console.WriteLine(tempDir); Console.Write("Press Enter"); System.Console.ReadLine(); int retry = 0; while (retry++ < 5) { try { di.Delete(true); break; } catch (IOException) { } catch (UnauthorizedAccessException) { } System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(100)); } if (retry >= 5) { var color = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; var id = System.Security.Principal.WindowsIdentity.GetCurrent(); var pri = new System.Security.Principal.WindowsPrincipal(id); if (pri.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator)) { //管理者権限で実行している場合は再起動時に削除可能にする MoveFileEx(tempDir, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT); Console.Error.WriteLine("一時フォルダがロックされているため再起動後に削除を試みます。"); //ただし空フォルダではない場合は失敗 } else { Console.Error.WriteLine("一時フォルダがロックされているため削除できませんでした。"); } Console.ForegroundColor = color; } else { Console.Error.WriteLine("一時フォルダが削除できました。"); } } [FlagsAttribute()] enum MoveFileFlags { MOVEFILE_REPLACE_EXISTING = 0x01, MOVEFILE_COPY_ALLOWED = 0x02, MOVEFILE_DELAY_UNTIL_REBOOT = 0x04, MOVEFILE_WRITE_THROUGH = 0x08, MOVEFILE_CREATE_HARDLINK = 0x10, MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 } [DllImport("kernel32.dll")] static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク manabubu 2015年5月13日 1:55
すべての返信
-
強制的に削除する方法はおそらく無いです。
他のプロセスが重要な処理の最中にもしも削除ができてしまった場合、そのプロセスのクラッシュを引き起こすことになりますよね。
#fm -forceは知りませんが、Windowsのrmdir /Qではメッセージが出ないだけで失敗しますそれよりもユーザーが簡単にアクセスできる場所にはテンポラリを作らないという方法を取った方がいいと思います。
using System; using System.Reflection; using System.Runtime.InteropServices; using System.IO; class Program { static void Main(string[] args) { //IsolatedStorageという見つけにくい場所を使う var storage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForAssembly(); //IsolatedStrageのフルパスをリフレクションで取り出し var pi = storage.GetType().GetProperty("RootDirectory", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); string tempDir = System.IO.Path.Combine((string)pi.GetValue(storage, null), "tempDir"); var di = new System.IO.DirectoryInfo(tempDir); di.Create(); //隠し属性にして見つけにくくする di.Attributes |= System.IO.FileAttributes.Hidden; //一時フォルダをカレントにしてコマンドプロンプトを開く System.Diagnostics.ProcessStartInfo si = new System.Diagnostics.ProcessStartInfo("cmd"); si.WorkingDirectory = tempDir; System.Diagnostics.Process.Start(si); Console.WriteLine(tempDir); Console.Write("Press Enter"); System.Console.ReadLine(); int retry = 0; while (retry++ < 5) { try { di.Delete(true); break; } catch (IOException) { } catch (UnauthorizedAccessException) { } System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(100)); } if (retry >= 5) { var color = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; var id = System.Security.Principal.WindowsIdentity.GetCurrent(); var pri = new System.Security.Principal.WindowsPrincipal(id); if (pri.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator)) { //管理者権限で実行している場合は再起動時に削除可能にする MoveFileEx(tempDir, null, MoveFileFlags.MOVEFILE_DELAY_UNTIL_REBOOT); Console.Error.WriteLine("一時フォルダがロックされているため再起動後に削除を試みます。"); //ただし空フォルダではない場合は失敗 } else { Console.Error.WriteLine("一時フォルダがロックされているため削除できませんでした。"); } Console.ForegroundColor = color; } else { Console.Error.WriteLine("一時フォルダが削除できました。"); } } [FlagsAttribute()] enum MoveFileFlags { MOVEFILE_REPLACE_EXISTING = 0x01, MOVEFILE_COPY_ALLOWED = 0x02, MOVEFILE_DELAY_UNTIL_REBOOT = 0x04, MOVEFILE_WRITE_THROUGH = 0x08, MOVEFILE_CREATE_HARDLINK = 0x10, MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 } [DllImport("kernel32.dll")] static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, MoveFileFlags dwFlags); }
個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)
- 回答としてマーク manabubu 2015年5月13日 1:55
-
他のOSと異なりWindowsの場合、ウィルス対策ソフトが稼働していることが多く、ファイルアクセスをすると対策ソフトが追跡して再オープンしてくるので、ファイル使用後の削除には(まだスキャン中なため)失敗しやすい印象です。
別のアプローチで、FileStreamクラスのコンストラクターにはFileOptionsを指定することができますが、この中にDeleteOnCloseがあります。これを指定するとファイルを閉じる際に自動的に削除されます。これはOSによる削除機能なので確実に消せるはずです。
- 回答としてマーク manabubu 2015年5月13日 1:55
-
他のOSと異なりWindowsの場合、ウィルス対策ソフトが稼働していることが多く、ファイルアクセスをすると対策ソフトが追跡して再オープンしてくるので、ファイル使用後の削除には(まだスキャン中なため)失敗しやすい印象です。
別のアプローチで、FileStreamクラスのコンストラクターにはFileOptionsを指定することができますが、この中にDeleteOnCloseがあります。これを指定するとファイルを閉じる際に自動的に削除されます。これはOSによる削除機能なので確実に消せるはずです。
ちょっと曖昧な記憶ですが、DeleteOnCloseは即座に本当に削除されるとは限らないため、ファイルが削除されたか確認しようとするとうまくいっていないように見える場合があるので注意してください。
※一時的に、エクスプローラからは見えるが開けない、削除もできない、実質的には削除済みに近いような状態になったりします。
遅くともマシンを再起動すれば、きちんと消えていることが確認できますが。
-
みなさま返信ありがとうございます。
説明不足でしたが、今回テンポラリとして作成するのはある圧縮ファイルを一時的に解凍するエリアになります。
このテンポラリは、本アプリでのみ参照するので、例え参照しているアプリが存在しそのアプリがクラッシュしたとしても強制削除したいと思っていたのですが、確かにウィルスチェックソフトの存在を忘れていました。
とすると、
- アプリの任意のタイミングでテンポラリを削除し、何らかの理由で削除出来ない場合は、次回削除でリトライ。
- そもそも圧縮ファイルの解凍先は必ずユニークになるようなフォルダをまず作成し、その下で解凍する。
という対応が必要そうですね。
色々と勉強になりました。ありがとうございました。
-
Tempフォルダーを使用している場合は、Windowsのディスククリーンアップにて削除されるので、それを期待するのも1つの手です。
ランダムなディレクトリ名を生成するにはPath.GetRandomFileName()が用意されています。