You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用FileSystemWatcher监听文件夹遇文件被占用IOException问题求助

解决FileSystemWatcher监听文件时的“文件被占用”异常

哥们儿,你这个问题太典型了——我当初做文件夹监听工具的时候也踩过一模一样的坑!核心原因是FileSystemWatcher的Created事件触发得太早:当系统刚创建文件的那一刻,这个事件就会触发,但此时写入文件的进程(比如记事本、其他业务程序)可能还没写完内容,文件还被它死死占用着,你的代码直接去ReadAllLines肯定会撞墙。首次成功纯粹是运气好,刚好那个文件瞬间写完了,后续文件写入稍微慢一点就触发了异常。

给你几个针对性的解决方案,一步步来:

1. 核心修复:等待文件释放占用

在读取文件前,一定要确保文件已经可以被访问。可以写一个辅助函数,循环尝试打开文件,直到成功或者超时:

Private Function WaitForFileAvailable(filePath As String, timeoutMs As Integer) As Boolean
    Dim startTime = DateTime.Now
    Do
        Try
            ' 尝试以读写方式打开文件,确认是否可访问
            Using fs = File.Open(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
                Return True
            End Using
        Catch ex As IOException
            ' 文件被占用,继续等待
            If DateTime.Now.Subtract(startTime).TotalMilliseconds > timeoutMs Then
                ' 超时返回失败,避免无限循环
                Return False
            End If
            Threading.Thread.Sleep(100) ' 每隔100ms重试一次,可根据需求调整
        End Try
    Loop
End Function

2. 修改你的print函数

把原来直接读取的逻辑改成先等待文件可用,再读取,并且用Using语句确保文件流正确释放,避免自己的进程占用文件:

Public Function print(ByVal path As String)
    ' 等待文件可用,超时设为5秒(可根据你的业务场景调整)
    If Not WaitForFileAvailable(path, 5000) Then
        ' 处理超时情况,比如记录日志
        Console.WriteLine($"文件 {path} 长时间被占用,放弃处理")
        Return
    End If

    ' 现在可以安全读取文件了
    Dim lines() As String
    Using sr = New StreamReader(path)
        lines = sr.ReadToEnd().Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
    End Using

    ' 处理每行内容(这里替换成你的业务操作)
    For Each line As String In lines
        ' 示例:Console.WriteLine("读取到内容:" & line)
    Next

    ' 最后删除文件,同样加个重试逻辑防止删除时又被占用
    Try
        File.Delete(path)
    Catch ex As IOException
        Console.WriteLine($"删除文件 {path} 失败:{ex.Message}")
    End Try
End Function

3. 优化FileSystemWatcher的配置

你的NotifyFilter设置可以精简一下,只关注和文件内容写入相关的项,避免不必要的事件触发:

Public Function startSrvc()
    watchfolder = New System.IO.FileSystemWatcher()
    watchfolder.Path = txtDirToWatch.Text
    ' 只关注文件名变化和文件写入完成的事件,减少无效触发
    watchfolder.NotifyFilter = IO.NotifyFilters.FileName Or IO.NotifyFilters.LastWrite
    AddHandler watchfolder.Created, AddressOf logchange
    ' 可选:如果有文件被修改的场景,也可以监听Changed事件
    ' AddHandler watchfolder.Changed, AddressOf logchange
    watchfolder.EnableRaisingEvents = True
End Function

额外注意点

  • 避免重复处理:FileSystemWatcher有时候会重复触发Created事件,你可以加一个标记(比如用HashSet记录正在处理的文件路径),防止同一个文件被多次处理。
  • 全局异常捕获:在logchange事件里也要加Try-Catch,不然一个文件处理失败会导致整个服务崩溃:
Private Sub logchange(ByVal source As Object, ByVal e As System.IO.FileSystemEventArgs)
    If e.ChangeType = IO.WatcherChangeTypes.Created Then
        Try
            print(e.FullPath.ToString)
        Catch ex As Exception
            Console.WriteLine($"处理文件 {e.FullPath} 出错:{ex.Message}")
        End Try
    End If
End Sub

这样修改后,你可以测试一下大文件或者慢写入的场景,应该就能稳定运行了。

内容的提问来源于stack exchange,提问作者stacks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 22:32:47