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

PowerShell文件监视器触发SQL Server上传脚本失败求助

解决PowerShell FileSystemWatcher触发SQL上传脚本延迟/失效问题

问题概述

已实现单独运行可正常将CSV文件上传至SQL Server的PowerShell脚本,但结合FileSystemWatcher使用时出现异常:

  • 初始脚本能检测到文件变更并输出提示,但上传脚本仅在按q退出时才执行
  • 修改为持续循环后,监视器完全不触发上传脚本

核心原因

  1. 控制台输入阻塞事件队列:原始do/until循环的[System.Console]::ReadKey($true)会阻塞PowerShell的事件处理线程,导致事件动作延迟到循环结束才执行
  2. 上传脚本硬编码文件名:上传脚本固定使用Test.csv,未接收Watcher检测到的实际变更文件路径
  3. 事件重复触发未处理: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 12:10:38