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

PowerShell FileSystemWatcher首次触发后报错问题求助

解决FileSystemWatcher移动CSV文件时的进程占用问题

我太懂这种FileSystemWatcher的坑了!你遇到的问题核心原因很明确:Created事件触发的时机其实是文件刚开始创建的时候,这时候写入文件的进程还没释放锁,直接调用Move-Item肯定会报错。再加上你原来的代码是批量移动目录下所有CSV,这就导致了后续触发时的混乱——第二次触发时第一次的文件可能还没完全释放,第三次触发又会重复处理之前失败的旧文件。

下面给你拆解问题,再附上完整的修复代码:

问题根源拆解

  1. 文件锁定冲突:Created事件触发时,文件大概率还处于被写入进程占用的状态,无法立即进行移动操作
  2. 批量操作逻辑缺陷:一次性移动所有CSV的写法,会导致重复处理文件,且无法精准对应触发事件的目标文件
  3. 无错误重试机制:遇到文件占用直接失败,后续事件触发时又会重复触发旧问题

针对性修复方案

1. 只处理触发事件的单个文件

利用事件参数里的$Event.SourceEventArgs获取刚创建的文件路径,只操作这个目标文件,避免批量操作带来的冲突。

2. 添加文件可用性检查+重试机制

通过尝试以独占模式打开文件,判断它是否已经写入完成、可以安全操作;如果被占用,就等待一段时间再重试,直到成功或达到最大重试次数。

3. 提前过滤CSV文件

给Watcher设置Filter属性,只监控.csv后缀的文件,减少无效的事件触发。

修正后的PowerShell代码

$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "E:\CreditAdj\cashpost"
$watcher.IncludeSubdirectories = $false
$watcher.Filter = "*.csv"  # 只监控CSV文件,减少无效触发
$watcher.EnableRaisingEvents = $true

$Action = {
    $filePath = $Event.SourceEventArgs.FullPath
    $targetPath = "\\server.company.com\cashpost"
    $maxRetries = 5  # 最大重试次数,可根据需求调整
    $retryDelay = 2000  # 每次重试间隔2秒,可根据需求调整

    for ($i=1; $i -le $maxRetries; $i++) {
        try {
            # 尝试以独占模式打开文件,验证是否可操作
            $fileStream = [System.IO.File]::Open(
                $filePath, 
                [System.IO.FileMode]::Open, 
                [System.IO.FileAccess]::ReadWrite, 
                [System.IO.FileShare]::None
            )
            $fileStream.Close()
            $fileStream.Dispose()

            # 文件可用,执行移动
            Move-Item -Path $filePath -Destination $targetPath -Force
            Write-Host "✅ 成功移动文件: $filePath"
            break
        }
        catch [System.IO.IOException] {
            Write-Host "⚠️ 第$i次尝试移动失败,文件被占用,等待重试..."
            Start-Sleep -Milliseconds $retryDelay
        }
        catch {
            Write-Host "❌ 移动文件时出现未知错误: $_"
            break
        }
    }

    if ($i -gt $maxRetries) {
        Write-Host "❌ 重试$maxRetries次后仍无法移动文件: $filePath"
    }
}

# 先注销已存在的同名事件订阅,避免重复注册
if (Get-EventSubscriber -SourceIdentifier CashpostCreated -ErrorAction SilentlyContinue) {
    Unregister-Event -SourceIdentifier CashpostCreated
}
$we1 = Register-ObjectEvent $watcher Created -SourceIdentifier CashpostCreated -Action $Action

额外提示

  • 如果你需要监控文件写入完成的状态,也可以考虑监听Changed事件,但配合重试机制的Created事件已经足够解决大部分场景
  • 重试次数和间隔可以根据你的业务场景调整,比如写入大文件时可以延长等待时间

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:32:47