PowerShell文件监视器触发SQL Server上传脚本失败求助
解决PowerShell FileSystemWatcher触发SQL上传脚本延迟/失效问题
问题概述
已实现单独运行可正常将CSV文件上传至SQL Server的PowerShell脚本,但结合FileSystemWatcher使用时出现异常:
- 初始脚本能检测到文件变更并输出提示,但上传脚本仅在按
q退出时才执行 - 修改为持续循环后,监视器完全不触发上传脚本
核心原因
- 控制台输入阻塞事件队列:原始
do/until循环的[System.Console]::ReadKey($true)会阻塞PowerShell的事件处理线程,导致事件动作延迟到循环结束才执行 - 上传脚本硬编码文件名:上传脚本固定使用
Test.csv,未接收Watcher检测到的实际变更文件路径 - 事件重复触发未处理:
Changed事件会因文件写入的多步骤触发多次,可能导致重复执行或文件占用问题
修正方案
1. 优化主脚本的事件等待逻辑
使用Wait-Event替代阻塞式控制台读取,确保事件能及时处理;同时传递变更文件的路径给上传脚本。
2. 修改上传脚本为接收参数
让上传脚本接受文件路径参数,避免硬编码,适配任意CSV文件的上传需求。
3. 处理文件写入完成判断
添加文件锁定检测,确保文件完全写入后再执行上传,避免读取未完成的文件。
修正后的完整代码
主监视器脚本
$folder = 'C:\Users\TDaly\Desktop\PowerShellTest' $filter = '*.csv' # 创建文件监视器 $watcher = New-Object System.IO.FileSystemWatcher $watcher.Path = $folder $watcher.Filter = $filter $watcher.IncludeSubdirectories = $false $watcher.EnableRaisingEvents = $true # 定义事件动作:传递文件路径并处理重复触发 $action = { $path = $Event.SourceEventArgs.FullPath $changeType = $Event.SourceEventArgs.ChangeType Write-Host "检测到文件 '$path' 发生 $changeType 变更 ($(Get-Date))" # 等待文件写入完成(避免读取未关闭的文件) $fileLocked = $true while ($fileLocked) { try { $fileStream = [System.IO.File]::Open($path, 'Open', 'Read', 'ReadWrite') $fileStream.Close() $fileLocked = $false } catch { Start-Sleep -Milliseconds 500 } } # 调用上传脚本并传递文件路径参数 & 'C:\Scripts\BulkInsertScript.ps1' -FilePath $path } # 注册Changed事件(同时可注册Created事件覆盖新文件创建场景) Register-ObjectEvent $watcher "Changed" -Action $action -SourceIdentifier "FileChangedWatcher" Register-ObjectEvent $watcher "Created" -Action $action -SourceIdentifier "FileCreatedWatcher" Write-Host "监视器已启动,监控文件夹:$folder" Write-Host "按 'q' 键退出..." # 非阻塞式等待事件和退出指令 while ($true) { if ([console]::KeyAvailable) { $key = [System.Console]::ReadKey($true) if ($key.KeyChar -eq 'q') { break } } # 等待事件触发,超时1秒避免CPU占用过高 $event = Wait-Event -Timeout 1 if ($event) { # 处理事件后自动移除 Remove-Event $event.SourceIdentifier } } # 清理资源 Unregister-Event -SourceIdentifier "FileChangedWatcher" Unregister-Event -SourceIdentifier "FileCreatedWatcher" $watcher.Dispose() Write-Host "监视器已退出"
上传脚本(BulkInsertScript.ps1)
param( [Parameter(Mandatory=$true)] [string]$FilePath ) # 设置数据库连接和BULK INSERT语句(使用传入的文件路径) $connectionString = "Server=test;Database=ScriptTest;User Id=test;Password=example;" $query = "BULK INSERT TestTable FROM '$FilePath' WITH (FIELDTERMINATOR = ',', ROWTERMINATOR = '\n', FIRSTROW = 2)" try { # 执行数据库操作 $connection = New-Object System.Data.SqlClient.SqlConnection($connectionString) $connection.Open() $command = $connection.CreateCommand() $command.CommandText = $query $rowsAffected = $command.ExecuteNonQuery() Write-Host "成功上传文件 '$FilePath',影响行数:$rowsAffected" } catch { Write-Error "上传失败:$_" } finally { # 确保连接关闭 if ($connection.State -ne 'Closed') { $connection.Close() } }
关键说明
- 添加
Created事件注册,覆盖文件新建的场景(原Changed事件可能无法捕获刚创建的文件) - 文件锁定检测逻辑确保只有当文件完全写入、释放锁后才执行上传
- 上传脚本通过参数接收文件路径,适配任意符合过滤规则的CSV文件
- 事件处理后调用
Remove-Event避免事件堆积
内容的提问来源于stack exchange,提问作者ted15555
相关产品推荐
相关产品推荐

