我有以下方法来删除具有提供路径的文件
private void DestroyFile(string path)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
if (File.Exists(path))
{
throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
}
}
catch (Exception ex)
{
throw ex;
}
}
Run Code Online (Sandbox Code Playgroud)
如果文件存在于 File.Delete 方法之后,我将收到抛出的 IOException。具体来说
System.IO.IOException): 无法删除文件: 'C:\Windows\TEMP\[FILE NAME]'。
我也确认在执行完成后在path变量中的位置不存在该文件。我想知道我是否在 File.Delete 之后更新文件系统和使用 File.Exists 再次检查它之间遇到竞争条件。有没有更好的方法平滑删除?我知道如果文件不存在, File.Delete 不会返回错误,所以这些检查可能有点多余。我应该检查文件是否在使用中而不是它是否存在?
一些重要的附加信息: 该程序可以并且确实经常成功运行,但最近经常看到此特定错误。
File.Delete将标记要删除的文件。只有当文件的所有句柄都关闭时,文件才会真正被删除(如果没有这样的句柄 - 它总是在 File.Delete 返回后被删除)。如DeleteFile winapi 函数(由 C# 使用File.Delete)所述:
DeleteFile 函数在关闭时标记要删除的文件。因此,在关闭文件的最后一个句柄之前不会发生文件删除
通常,您删除的文件没有打开的句柄。或者,如果有打开的句柄 - 它们通常没有“删除”共享(此共享允许另一个进程将文件标记为删除),因此当您尝试删除此类文件时 - 它要么被删除(没有打开的句柄)要么访问被拒绝或类似的异常被抛出(一些句柄,但没有删除共享)。
但是,有时某些软件(例如防病毒软件或搜索索引器)可能会使用“删除”共享打开任意文件并将它们保留一段时间。如果您尝试删除此类文件 - 它不会出错,并且当该软件关闭其句柄时,文件确实会被删除。但是,File.Exists对于此类“待删除”文件,将返回 true。
你可以用这个简单的程序重现这个问题:
public class Program {
public static void Main() {
string path = @"G:\tmp\so\tmp.file";
// create file with delete share and don't close handle
var file = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete);
DestroyFile(path);
GC.KeepAlive(file);
}
private static void DestroyFile(string path) {
try {
if (File.Exists(path)) {
// no error
File.Delete(path);
}
// but still exists
if (File.Exists(path)) {
throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
}
}
catch (Exception ex) {
throw ex;
}
}
}
Run Code Online (Sandbox Code Playgroud)
您可以File.Exists在上面的程序中永远重试检查 - 文件将一直存在,直到您关闭句柄。
所以这就是你的情况 - 一些程序打开了这个文件的句柄FileShare.Delete.
你应该预料到这种情况。例如 - 只需删除该File.Exists检查,因为您将文件标记为删除,无论如何它都会被删除。
| 归档时间: |
|
| 查看次数: |
3325 次 |
| 最近记录: |