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

PowerShell中FileSystemWatcher动作期间暂停与重启方案问询

解决FileSystemWatcher事件排队与重启问题

我明白你的痛点——在处理信号灯的60秒等待期内,新的文件创建事件会排队,导致信号灯刚恢复就又变红,而且你尝试停止后重启Watcher失败。核心问题在于你之前错误地Dispose了Watcher对象(一旦Dispose就无法复用),同时缺少复用Watcher配置的逻辑导致代码冗余。

解决方案思路

  • 封装Watcher配置为函数:把创建和配置FileSystemWatcher的逻辑抽成函数,这样重启时直接调用即可,避免重复代码。
  • 暂停而非销毁Watcher:处理事件时,只需要将EnableRaisingEvents设为$false暂停监听,处理完逻辑后再设为$true恢复,不需要Dispose对象(Dispose会彻底释放,无法再次使用)。
  • 避免事件队列堆积:暂停监听后,新的文件创建事件不会被加入队列,直到恢复监听才会重新检测。

修改后的完整代码

Write-Host "Auto Relay Change On Detection"
Add-Type -AssemblyName PresentationCore,PresentationFramework
$settingsFile = "$PSScriptRoot\settings.json"
$j = Get-Content -Raw -Path $settingsFile | ConvertFrom-Json
$PathToMonitor = $j.imageFolder

If(!(test-path $PathToMonitor)) {
    New-Item -ItemType Directory -Force -Path $PathToMonitor
}

# 封装FileSystemWatcher配置逻辑,方便复用
function Initialize-FileSystemWatcher {
    param(
        [string]$Path,
        [bool]$IncludeSubdirectories = $true
    )
    $watcher = New-Object System.IO.FileSystemWatcher
    $watcher.Path = $Path
    $watcher.IncludeSubdirectories = $IncludeSubdirectories
    $watcher.EnableRaisingEvents = $true
    return $watcher
}

# 初始化Watcher
$FileSystemWatcher = Initialize-FileSystemWatcher -Path $PathToMonitor

# 定义文件变更检测时执行的代码
$Action = {
    $details = $event.SourceEventArgs
    $Name = $details.Name
    $FullPath = $details.FullPath
    $ChangeType = $details.ChangeType
    $Timestamp = $event.TimeGenerated

    switch ($ChangeType) {
        'Created' {
            $text = "File {0} was created." -f $Name
            Write-Host $text -ForegroundColor Yellow
            Write-Host "Relay = detected at $(Get-Date)" -ForegroundColor Yellow

            # 暂停Watcher事件监听,避免新事件排队
            $event.MessageData.Watcher.EnableRaisingEvents = $false

            try {
                # 执行API调用(替换成你的继电器控制代码)
                $timeout = $event.MessageData.Timer
                Start-Sleep -s $timeout
                # 执行恢复绿色的API调用
                Write-Host "Relay = default at $(Get-Date)" -ForegroundColor Yellow
            }
            finally {
                # 无论是否出错,都恢复Watcher监听
                $event.MessageData.Watcher.EnableRaisingEvents = $true
            }
        }
        'Changed' { Write-Host "CHANGE: $FullPath" }
        'Deleted' { Write-Host "DELETED: $FullPath" }
        'Renamed' { Write-Host "RENAMED: $FullPath" }
        default {
            Write-Host $_ -ForegroundColor Red -BackgroundColor White
        }
    }
}

# 添加事件处理器时,传递Watcher和定时器参数给Action
$handlers = Register-ObjectEvent -InputObject $FileSystemWatcher -EventName Created -Action $Action -SourceIdentifier FSCreate -MessageData @{
    Watcher = $FileSystemWatcher
    Timer = $j.timer
}

try {
    do {
        Wait-Event -Timeout 1
    } while ($true)
} finally {
    Unregister-Event -SourceIdentifier FSCreate
    $handlers | Remove-Job
    $FileSystemWatcher.EnableRaisingEvents = $false
    $FileSystemWatcher.Dispose()
    Write-Host "Event Handler disabled."
}

关键修改说明

  1. 封装Initialize-FileSystemWatcher函数:把Watcher的创建和配置逻辑抽离,后续如果需要重启(比如异常后),直接调用这个函数即可,避免代码重复。
  2. Action中操作Watcher状态:通过-MessageData将Watcher对象和定时器参数传递给Action脚本块,这样在处理事件时可以直接修改EnableRaisingEvents来暂停/恢复监听,不需要重新创建Watcher。
  3. try/finally确保监听恢复:即使处理过程中出现错误,也会通过finally块恢复Watcher的监听状态,避免程序陷入无响应。
  4. 避免Dispose重启:不再在Action中Dispose Watcher,只是切换EnableRaisingEvents状态,这样Watcher对象可以持续复用,解决重启失败的问题。

这样修改后,当有文件创建时,Watcher会暂停监听,直到60秒信号灯恢复后才重新开始检测新文件,彻底解决事件排队的问题,同时代码也更简洁易维护。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 10:47:43