我有一个应用程序,我正在寻找一个文本文件,如果对文件做了任何更改,我使用OnChanged事件处理程序来处理事件。我正在使用NotifyFilters。LastWriteTime,但是事件仍然被触发两次。这是代码。

public void Initialize()
{
   FileSystemWatcher _fileWatcher = new FileSystemWatcher();
  _fileWatcher.Path = "C:\\Folder";
  _fileWatcher.NotifyFilter = NotifyFilters.LastWrite;
  _fileWatcher.Filter = "Version.txt";
  _fileWatcher.Changed += new FileSystemEventHandler(OnChanged);
  _fileWatcher.EnableRaisingEvents = true;
}

private void OnChanged(object source, FileSystemEventArgs e)
{
   .......
}

在我的情况下,OnChanged被调用两次,当我改变文本文件version.txt并保存它。


当前回答

如果你注册了OnChanged事件,那么在修改之前删除被监视的文件可能会起作用,只要你只需要监视OnChange事件。

其他回答

In my case need to get the last line of a text file that is inserted by other application, as soon as insertion is done. Here is my solution. When the first event is raised, i disable the watcher from raising others, then i call the timer TimeElapsedEvent because when my handle function OnChanged is called i need the size of the text file, but the size at that time is not the actual size, it is the size of the file imediatelly before the insertion. So i wait for a while to proceed with the right file size.

private FileSystemWatcher watcher = new FileSystemWatcher();
...
watcher.Path = "E:\\data";
watcher.NotifyFilter = NotifyFilters.LastWrite ;
watcher.Filter = "data.txt";
watcher.Changed += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = true;

...

private void OnChanged(object source, FileSystemEventArgs e)
   {
    System.Timers.Timer t = new System.Timers.Timer();
    try
    {
        watcher.Changed -= new FileSystemEventHandler(OnChanged);
        watcher.EnableRaisingEvents = false;

        t.Interval = 500;
        t.Elapsed += (sender, args) => t_Elapsed(sender, e);
        t.Start();
    }
    catch(Exception ex) {
        ;
    }
}

private void t_Elapsed(object sender, FileSystemEventArgs e) 
   {
    ((System.Timers.Timer)sender).Stop();
       //.. Do you stuff HERE ..
     watcher.Changed += new FileSystemEventHandler(OnChanged);
     watcher.EnableRaisingEvents = true;
}

您可以尝试打开它进行写入,如果成功,则可以假设其他应用程序已经处理了该文件。

private void OnChanged(object source, FileSystemEventArgs e)
{
    try
    {
        using (var fs = File.OpenWrite(e.FullPath))
        {
        }
        //do your stuff
    }
    catch (Exception)
    {
        //no write access, other app not done
    }
}

仅仅打开它以供写入似乎不会引发已更改的事件。所以应该是安全的。

我在这里有一个非常快速和简单的解决方法,它对我来说确实有效,无论事件偶尔会被触发一次或两次或多次,检查它:

private int fireCount = 0;
private void inputFileWatcher_Changed(object sender, FileSystemEventArgs e)
    {
       fireCount++;
       if (fireCount == 1)
        {
            MessageBox.Show("Fired only once!!");
            dowork();
        }
        else
        {
            fireCount = 0;
        }
    }
}

我必须结合以上文章中的几个想法,并添加文件锁定检查,让它为我工作:

FileSystemWatcher fileSystemWatcher;

private void DirectoryWatcher_Start()
{
    FileSystemWatcher fileSystemWatcher = new FileSystemWatcher
    {
        Path = @"c:\mypath",
        NotifyFilter = NotifyFilters.LastWrite,
        Filter = "*.*",
        EnableRaisingEvents = true
    };

    fileSystemWatcher.Changed += new FileSystemEventHandler(DirectoryWatcher_OnChanged);
}

private static void WaitUntilFileIsUnlocked(String fullPath, Action<String> callback, FileAccess fileAccess = FileAccess.Read, Int32 timeoutMS = 10000)
{
    Int32 waitMS = 250;
    Int32 currentMS = 0;
    FileInfo file = new FileInfo(fullPath);
    FileStream stream = null;
    do
    {
        try
        {
            stream = file.Open(FileMode.Open, fileAccess, FileShare.None);
            stream.Close();
            callback(fullPath);
            return;
        }
        catch (IOException)
        {
        }
        finally
        {
            if (stream != null)
                stream.Dispose();
        }
        Thread.Sleep(waitMS);
        currentMS += waitMS;
    } while (currentMS < timeoutMS);
}    

private static Dictionary<String, DateTime> DirectoryWatcher_fileLastWriteTimeCache = new Dictionary<String, DateTime>();

private void DirectoryWatcher_OnChanged(Object source, FileSystemEventArgs ev)
{
    try
    {
        lock (DirectoryWatcher_fileLastWriteTimeCache)
        {
            DateTime lastWriteTime = File.GetLastWriteTime(ev.FullPath);
            if (DirectoryWatcher_fileLastWriteTimeCache.ContainsKey(ev.FullPath))
            {
                if (DirectoryWatcher_fileLastWriteTimeCache[ev.FullPath].AddMilliseconds(500) >= lastWriteTime)
                    return;     // file was already handled
            }

            DirectoryWatcher_fileLastWriteTimeCache[ev.FullPath] = lastWriteTime;
        }

        Task.Run(() => WaitUntilFileIsUnlocked(ev.FullPath, fullPath =>
        {
            // do the job with fullPath...
        }));

    }
    catch (Exception e)
    {
        // handle exception
    }
}

我是这样处理双重创造问题的,忽略了第一个事件:

Private WithEvents fsw As New System.IO.FileSystemWatcher
Private complete As New List(Of String)

Private Sub fsw_Created(ByVal sender As Object, _
    ByVal e As System.IO.FileSystemEventArgs) Handles fsw.Created

    If Not complete.Contains(e.FullPath) Then
        complete.Add(e.FullPath)

    Else
        complete.Remove(e.FullPath)
        Dim th As New Threading.Thread(AddressOf hprocess)
        th.Start(e)

    End If

End Sub