我正在使用C#,但看不到检测挂起删除的方法。该文件是使用FileStream对象打开的。是否有一些在C#或其他Windows函数中检测删除操作的方法?
using System;
using System.Text;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
internal static class Native
{
[DllImport("kernel32.dll", SetLastError = true)]
public extern static bool GetFileInformationByHandleEx(IntPtr hFile,
int FileInformationClass,
IntPtr lpFileInformation,
uint dwBufferSize);
public struct FILE_STANDARD_INFO
{
public long AllocationSize;
public long EndOfFile;
public uint NumberOfLinks;
public byte DeletePending;
public byte Directory;
}
public const int FileStandardInfo = 1;
}
internal static class Program
{
public static bool IsDeletePending(FileStream fs)
{
IntPtr buf = Marshal.AllocHGlobal(4096);
try
{
IntPtr handle = fs.SafeFileHandle.DangerousGetHandle();
if (!Native.GetFileInformationByHandleEx(handle,
Native.FileStandardInfo,
buf,
4096))
{
Exception ex = new Exception("GetFileInformationByHandleEx() failed");
ex.Data["error"] = Marshal.GetLastWin32Error();
throw ex;
}
else
{
Native.FILE_STANDARD_INFO info = Marshal.PtrToStructure<Native.FILE_STANDARD_INFO>(buf);
return info.DeletePending != 0;
}
}
finally
{
Marshal.FreeHGlobal(buf);
}
}
public static int Main(string[] args)
{
TimeSpan MAX_WAIT_TIME = TimeSpan.FromSeconds(10);
if (args.Length == 0)
{
args = new string[] { "deleteme.txt" };
}
for (int i = 0; i < args.Length; ++i)
{
string filename = args[i];
FileStream fs = null;
try
{
fs = File.Open(filename,
FileMode.CreateNew,
FileAccess.Write,
FileShare.ReadWrite | FileShare.Delete);
byte[] buf = new byte[4096];
UTF8Encoding utf8 = new UTF8Encoding(false);
string text = "hello world!\r\n";
int written = utf8.GetBytes(text, 0, text.Length, buf, 0);
fs.Write(buf, 0, written);
fs.Flush();
Console.WriteLine("{0}: created and wrote line", filename);
DateTime t0 = DateTime.UtcNow;
for (;;)
{
Thread.Sleep(16);
if (IsDeletePending(fs))
{
Console.WriteLine("{0}: detected pending delete", filename);
break;
}
if (DateTime.UtcNow - t0 > MAX_WAIT_TIME)
{
Console.WriteLine("{0}: timeout reached with no delete", filename);
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine("{0}: {1}", filename, ex.Message);
}
finally
{
if (fs != null)
{
Console.WriteLine("{0}: closing", filename);
fs.Dispose();
}
}
}
return 0;
}
}
FileSystemWatcher
(FSW)。当文件消失时,FSW可以设置一个标志以中断处理:private bool _fileExists = true;
public void Process(string pathToOriginalFile, string pathToCopy)
{
File.Copy(pathToOriginalFile, pathToCopy);
FileSystemWatcher watcher = new FileSystemWatcher();
watcher.Path = pathToOriginalFile;
watcher.Deleted += new FileSystemEventHandler(OnFileDeleted);
bool doneProcessing = false;
watcher.EnableRaisingEvents = true;
while(_fileExists && !doneProcessing)
{
// process the copy here
}
...
}
private void OnFileDeleted(object source, FileSystemEventArgs e)
{
_fileExists = false;
}
FileSystemWatcher可能是最接近的东西,但它无法检测“挂起”删除;当文件被删除时,FileSystemWatcher会触发一个事件,您可以附加一个处理程序来优雅地中断文件处理。如果您在打开文件时获取的锁定(或缺少锁定)使得文件可以被删除,那么当发生这种情况时,只需关闭您的只读FileStream即可不影响文件系统。
文件监视器的基本步骤是创建一个,将FileInfo对象的实例传递给构造函数。可以通过仅实例化一个并将其作为字符串传递文件的路径和文件名来廉价地创建FileInfos。然后,将其NotifyFilter设置为您要在此文件上监视的文件系统修改类型。最后,将您的进程的事件处理程序附加到OnDeleted事件。此事件处理程序可能非常简单,只需设置某个位标志,您的主进程可以读取该标志,并关闭FileStream。然后,您将在下一次尝试使用流时收到异常;捕获它,读取标志,如果设置了标志,则优雅地停止执行文件操作。您还可以将文件处理放在单独的工作线程中,事件处理程序可以告诉线程以某种优雅的方法死亡。
我会使用不同的信号机制。 (我假设所有文件访问都在您的控制范围内,而不是来自封闭的外部程序,主要是由于所使用的标志。)
在这些限制下,我唯一能想到的“解决方案”是对文件访问进行轮询并检查您收到的异常(如果有)。也许有更加棘手的东西(比 win32 文件 API 更低级别的东西?!),但这已经走上了“艰难的道路” :-)
不,没有干净的方法来做到这一点。如果您担心其他进程打开和/或修改文件,则 oplocks 可以帮助您。但是,如果您只是想通知何时将删除处理设置为已删除,那么没有直接的方法可以做到这一点(除非构建文件系统过滤器、挂钩 API 等,所有这些都对应用程序而言都很可怕,除非有非常充分的理由)。