我正在尝试监控我的下载文件夹并在下载完成时触发命令行操作。这与另一个问题非常相似,如何监视文件夹并在创建或编辑文件时触发命令行操作?
我已经实现了得票最多的答案,但是当我运行它时,我发现输出令人困惑。
### SET FOLDER TO WATCH + FILES TO WATCH + SUBFOLDERS YES/NO
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "Z:\UnprocessedDownloads"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
### DEFINE ACTIONS AFTER AN EVENT IS DETECTED
$action = { $path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$logline = "$(Get-Date -f o), $changeType, $path"
Add-content "Z:\log.txt" -value $logline
}
### DECIDE WHICH EVENTS SHOULD BE WATCHED
Register-ObjectEvent $watcher "Created" -Action $action
Register-ObjectEvent $watcher "Changed" -Action $action
Register-ObjectEvent $watcher "Deleted" -Action $action
Register-ObjectEvent $watcher "Renamed" -Action $action
while ($true) {sleep 5}
我应该指出,有问题的下载是由 Chrome 创建的,这也许可以解释发生了什么。据我所知,这一系列事件如下:
- 将创建一个具有预期文件名的文件。
- 先前创建的文件被立即删除。
- 具有预期文件名的文件,以及.cr下载已附加,已创建。
- 该文件记录了两到三个变化(我测试的文件中,如果变化是几 KB 则显示两个,但 100MB 到 10GB 的文件记录了三个)。
- 该文件被重命名,删除了.cr下载。
- 然后,此文件又记录了另外两到三处更改(我找不到发生多少次更改的原因或韵律)。
- 已完成,无需人工干预,其他任何事情都不会被记录。
就是这样。我不知道如何判断文件是否真正“完成”,除非观察重命名事件,然后等待任意秒数(有时,最后记录的更改需要大约 5 秒才能发生 - 我刚刚意识到这可能是由于脚本中的 sleep 5),也许是 10。
有人能解释一下这是怎么回事吗?有什么建议或替代方案吗?我并不依赖 PowerShell,只是觉得它和文件系统监视程序很适合这项任务。我更喜欢在保留自动化的同时尽可能减少开销的东西。
FWIW,这是我的测试的摘录(并不广泛;注意 - 我确实调整了日志以显示毫秒):
2019-01-02T22:03:03.6712039-05:00, Created, Z:\Unprocessed\test (1).jpg
2019-01-02T22:03:03.7242040-05:00, Deleted, Z:\Unprocessed\test (1).jpg
2019-01-02T22:03:03.7252054-05:00, Created, Z:\Unprocessed\test (1).jpg.crdownload
2019-01-02T22:03:03.7252054-05:00, Changed, Z:\Unprocessed\test (1).jpg.crdownload
2019-01-02T22:03:08.7265875-05:00, Changed, Z:\Unprocessed\test (1).jpg.crdownload
2019-01-02T22:03:08.7305994-05:00, Renamed, Z:\Unprocessed\test (1).jpg
2019-01-02T22:03:08.7315887-05:00, Changed, Z:\Unprocessed\test (1).jpg
2019-01-02T22:03:08.7315887-05:00, Changed, Z:\Unprocessed\test (1).jpg
2019-01-02T22:03:13.7348367-05:00, Changed, Z:\Unprocessed\test (1).jpg
2019-01-02T22:09:28.7729475-05:00, Deleted, Z:\Unprocessed\10GB.bin
2019-01-02T22:09:33.7742846-05:00, Created, Z:\Unprocessed\1GB.bin
2019-01-02T22:09:33.7762852-05:00, Deleted, Z:\Unprocessed\1GB.bin
2019-01-02T22:09:33.7772866-05:00, Created, Z:\Unprocessed\1GB.bin.crdownload
2019-01-02T22:09:33.7782853-05:00, Changed, Z:\Unprocessed\1GB.bin.crdownload
2019-01-02T22:09:33.7792825-05:00, Changed, Z:\Unprocessed\1GB.bin.crdownload
2019-01-02T22:10:28.7850646-05:00, Changed, Z:\Unprocessed\1GB.bin.crdownload
2019-01-02T22:10:28.7860648-05:00, Renamed, Z:\Unprocessed\1GB.bin
2019-01-02T22:10:28.7870652-05:00, Changed, Z:\Unprocessed\1GB.bin
2019-01-02T22:10:28.7870652-05:00, Changed, Z:\Unprocessed\1GB.bin
2019-01-02T22:10:28.7880654-05:00, Changed, Z:\Unprocessed\1GB.bin
2019-01-02T22:11:13.7928495-05:00, Created, Z:\Unprocessed\test (2).jpg
2019-01-02T22:11:13.7938482-05:00, Deleted, Z:\Unprocessed\test (2).jpg
2019-01-02T22:11:13.7938482-05:00, Created, Z:\Unprocessed\test (2).jpg.crdownload
2019-01-02T22:11:13.7948490-05:00, Changed, Z:\Unprocessed\test (2).jpg.crdownload
2019-01-02T22:11:18.7972830-05:00, Changed, Z:\Unprocessed\test (2).jpg.crdownload
2019-01-02T22:11:18.7982945-05:00, Renamed, Z:\Unprocessed\test (2).jpg
2019-01-02T22:11:18.7992839-05:00, Changed, Z:\Unprocessed\test (2).jpg
2019-01-02T22:11:18.8002947-05:00, Changed, Z:\Unprocessed\test (2).jpg
2019-01-02T22:11:23.8011169-05:00, Changed, Z:\Unprocessed\test (2).jpg
答案1
试试这个。我修改了原版以添加更多逻辑。不确定这个版本是否可靠。让我知道它是否可靠。
# create an array that tracks each file
$global:files = @()
# where we will move the file once it is free
$destination = "C:\destination"
$watcher = New-Object System.IO.FileSystemWatcher
$watcher.Path = "C:\source"
$watcher.Filter = "*.*"
$watcher.IncludeSubdirectories = $true
$watcher.EnableRaisingEvents = $true
$action = {
$path = $Event.SourceEventArgs.FullPath
$changeType = $Event.SourceEventArgs.ChangeType
$logline = "$(Get-Date -f o), $changeType, $path"
Add-content "C:\log.txt" -value $logline
Write-Host $logline
if($changeType -eq "Renamed" -and $path.Split(".")[-1] -ne "crdownload") {
Write-Host -ForegroundColor Green "Found the file we need! $path"
Add-content "C:\log.txt" -value "Found the file we need! $path"
$global:files += $path
}
}
Register-ObjectEvent $watcher "Created" -Action $action
Register-ObjectEvent $watcher "Changed" -Action $action
Register-ObjectEvent $watcher "Deleted" -Action $action
Register-ObjectEvent $watcher "Renamed" -Action $action
while ($true) {
# if there are any files to process, check if they are locked
if($global:files) {
$global:files | % {
$file = $_
# assume the file is locked
$fileFree = $false
Write-Host -ForegroundColor Yellow "Checking if the file is locked... ($file)"
Add-content "C:\log.txt" -value "Checking if the file is locked... ($_)"
# true = file is free
# false = file is locked
try {
[IO.File]::OpenWrite($file).close();Write-Host -ForegroundColor Green "File is free! ($file)"
Add-content "C:\log.txt" -value "File is free! ($file)"
$fileFree = $true
}
catch {
Write-Host -ForegroundColor Red "File is Locked ($file)"
Add-content "C:\log.txt" -value "File is Locked ($file)"
}
if($fileFree) {
# do what we want with the file, since it is free
Move-Item $file $destination
Write-Host -ForegroundColor Green "Moving file ($file)"
Add-content "C:\log.txt" -value "Moving file ($file)"
# make sure we don't progress until the file has finished moving
while(Test-Path $file) {
Sleep 1
}
# remove the current file from the array
Write-Host -ForegroundColor Green "Done processing this file. ($file)"
Add-content "C:\log.txt" -value "Done processing this file. ($file)"
$global:files = $global:files | ? { $_ -ne $file }
}
}
}
sleep 2
}
- 这将监听
Renamed
文件扩展名不是“crdownload”的事件,帮助我们获取实际路径/文件/扩展名,而不是临时文件的信息。找到匹配项后,它会存储在数组中,这样我们就可以同时处理多个文件。 - 一旦数组包含一个或多个文件名,就会检查每个文件,看它当前是否被锁定或是否空闲。如果空闲,则将其移动到
$destination
。您可以将所需操作从更改Move-Item
为您想要的任何操作。 - 一旦文件移动成功,它将从阵列中删除。
要知道,你所看到的多个Changed
事件将是预期的(从 Chrome 下载时也会出现这种情况):
常见的文件系统操作可能会引发多个事件。例如,当文件从一个目录移动到另一个目录时,可能会引发多个 OnChanged 事件以及一些 OnCreated 和 OnDeleted 事件。移动文件是一项复杂的操作,由多个简单操作组成,因此会引发多个事件。同样,某些应用程序(例如防病毒软件)可能会引发 FileSystemWatcher 检测到的其他文件系统事件。
您可能想要删除添加的Write-Host
行。您可能还想在终止捕获中添加以下内容,以正常终止已注册的事件:
Get-EventSubscriber | ? { $_.EventName -in "Created","Changed","Deleted","Renamed" } | Unregister-Event
灵感。