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

为何向D:\Folder放入PDF时,脚本内Merge PDFs.bat会多次执行?需仅执行一次

解决FileSystemWatcher触发多次导致Bat重复执行的问题

嗨,这个问题我之前踩过一模一样的坑!你的PowerShell脚本里Merge PDFs.bat多次执行,核心原因是FileSystemWatcher的Created事件会被系统的多步文件操作触发多次,再加上脚本没有做去重处理,自然就重复执行了。

为什么会多次触发?

主要有这两个常见场景:

  • 文件写入的分步操作:当你把PDF复制到目标目录时,系统不是一次性把文件写完的——通常会先创建一个空文件,然后逐步写入内容,最后可能还要修改文件的属性(比如修改时间)。每一步操作都可能触发Created或者关联的事件,导致你的脚本多次捕获到“文件创建”的信号。
  • 系统/第三方程序的额外操作:比如杀毒软件会自动扫描新文件,Windows资源管理器会生成PDF的缩略图,这些操作都会对新创建的文件进行读写访问,间接触发FileSystemWatcher的事件。

而且你脚本里的Start-Sleep -s 15只是延迟执行,但并没有判断“这个文件是不是已经处理过”,所以只要有事件触发,就会再跑一次bat。

怎么修改脚本解决问题?

我们需要给脚本加两个关键逻辑:判断文件是否完全写入磁盘 + 记录已处理的文件避免重复执行。下面是修改后的完整脚本:

# 定义全局哈希表,用来记录已经处理过的文件路径
$processedFiles = @{}

$folder = 'D:\Folder'
$filter = '*.PDF'
$fsw = New-Object IO.FileSystemWatcher $folder, $filter -Property @{
    IncludeSubdirectories = $false
    NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}

Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
    param($event)
    $fileName = $event.SourceEventArgs.Name
    $fullFilePath = Join-Path $event.SourceEventArgs.FullPath.DirectoryName $fileName

    # 1. 跳过已经处理过的文件
    if ($script:processedFiles.ContainsKey($fullFilePath)) {
        Write-Host "跳过已处理文件: $fileName"
        return
    }

    # 2. 等待文件完全写入(判断文件是否被锁定)
    $isFileLocked = $true
    while ($isFileLocked) {
        try {
            # 尝试以读写方式打开文件,能打开说明文件已写完
            $fileStream = [System.IO.File]::Open($fullFilePath, 'Open', 'ReadWrite', 'None')
            $fileStream.Close()
            $isFileLocked = $false
        }
        catch {
            # 文件还在被写入,等待500毫秒再重试
            Start-Sleep -Milliseconds 500
        }
    }

    # 3. 标记当前文件为已处理
    $script:processedFiles[$fullFilePath] = $true
    # 可选:清理哈希表中已不存在的文件记录,避免内存占用过大
    $script:processedFiles.Keys | Where-Object { -not (Test-Path $_) } | ForEach-Object {
        $script:processedFiles.Remove($_)
    }

    # 4. 执行合并脚本
    Write-Host "处理文件: $fileName,执行合并bat"
    Invoke-Item 'C:\Merge PDF\Merge PDFs.bat'
}

关键逻辑说明

  • 全局哈希表$processedFiles:因为Action块有自己独立的作用域,所以用script:前缀来访问全局的哈希表,记录已经处理过的文件路径,避免重复触发。
  • 文件锁定判断:通过尝试以读写方式打开文件,来确认文件是否已经完全写入磁盘——如果文件还在复制/写入中,系统会锁定文件,这时候我们就等待一会儿再重试,确保bat处理的是完整的PDF文件。
  • 清理旧记录:定期移除哈希表中已经不存在的文件路径,防止哈希表随着时间变得过大,占用不必要的内存。

这样修改后,不管FileSystemWatcher触发多少次事件,同一个PDF文件只会触发一次bat的执行啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 09:42:37