下面的代码正在检查指定目录$folderCompleted
中的新文件。
当前,当一个小文件被放置到该目录(~1MB)中时,移动项命令和其他文件读取检查将成功完成。
但是,当一个大文件被移动到这个目录中时,在文件被完全移动(复制)到该目录之前,将调用对象事件。这将导致文件检查和移动项命令失败,因为该文件仍在使用中。
# File Watcher
$filter = '*.*'
$fsw = New-Object IO.FileSystemWatcher $folderCompleted, $filter -Property @{
IncludeSubdirectories = $true
NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'
}
$onCreated = Register-ObjectEvent $fsw Created -SourceIdentifier FileCreated -Action {
$path = $Event.SourceEventArgs.FullPath
$name = $Event.SourceEventArgs.Name
$changeType = $Event.SourceEventArgs.ChangeType
$timeStamp = $Event.TimeGenerated
Write-Host "The file '$name' was $changeType at $timeStamp"
# File Checks
# Move File
Move-Item $path -Destination $destinationPath -Verbose
}
如何进行检查,以确定文件是否仍在复制?
发布于 2020-06-13 14:01:16
在上面贴出我的评论后不久就解决了这个问题。其他答案可能相似,但最终将此函数添加到脚本顶部。
# function Test-FileLock
function Test-FileLock {
param ([parameter(Mandatory=$true)][string]$Path)
$oFile = New-Object System.IO.FileInfo $Path
if ((Test-Path -Path $Path) -eq $false)
{
return $false
}
try
{
$oStream = $oFile.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None)
if ($oStream)
{
$oStream.Close()
}
$false
}
catch
{
# file is locked by a process.
return $true
}
}
在$onCreated部分的变量部分之后添加此代码。
# Test File Lock
Do {
$filetest = Test-FileLock -Path $path
sleep -Seconds 5
} While ($filetest -eq $true)
发布于 2020-06-13 03:44:19
尝尝这个。(以前也有类似的担忧)。
事件触发器是在同步哈希表中收集所有受影响的项,附加的scriptblock处理所有项,但只有当它们准备好读取而不是锁定时才会处理文件。如果文件被锁定,您将在控制台中看到它。只需尝试复制一个文件>1GB,并观察输出。
脚本块$fSItemEventProcessingJob处理这些项(比如复制到备份文件),最初创建它是为了将其用于“开始-作业”。但是您无法访问和修改会话中的该后台作业中的哈希表。因此,它是一个简单的scriptblock执行。
要停止所有操作,只需按CTRL + C键即可。这仍然会执行"finally“块,取消注册并处理所有内容。
PS:脚本只是一个测试,只在我的PC上进行本地测试。
Clear-Host
$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
$fileSystemWatcherDirPath = 'C:\temp'
$fileSystemWatcherFilter = '*.*'
$fileSystemWatcher = [System.IO.FileSystemWatcher]::new($fileSystemWatcherDirPath , $fileSystemWatcherFilter)
$fileSystemWatcher.IncludeSubdirectories = $true
$fileSystemWatcher.EnableRaisingEvents = $true
$fileSystemWatcher.NotifyFilter = [System.IO.NotifyFilters]::FileName -bor [System.IO.NotifyFilters]::DirectoryName -bor [System.IO.NotifyFilters]::LastWrite # [System.Linq.Enumerable]::Sum([System.IO.NotifyFilters].GetEnumValues())
# Create syncronized hashtable
$syncdFsItemEventHashT = [hashtable]::Synchronized([hashtable]::new())
$fileSystemWatcherAction = {
try {
$fsItemEvent = [pscustomobject]@{
EventIdentifier = $Event.EventIdentifier
SourceIdentifier = $Event.SourceIdentifier
TimeStamp = $Event.TimeGenerated
FullPath = $Event.SourceEventArgs.FullPath
ChangeType = $Event.SourceEventArgs.ChangeType
}
# Collecting event in synchronized hashtable (overrides existing keys so that only the latest event details are available)
$syncdFsItemEventHashT[$fsItemEvent.FullPath] = $fsItemEvent
} catch {
Write-Host ($_ | Format-List * | Out-String ) -ForegroundColor red
}
}
# Script block which processes collected events and do further actions like copying for backup, etc...
# That scriptblock was initially used to test "Start-Job". Unfortunately it's not possible to access and modify the synchronized hashtable created within this scope.
$fSItemEventProcessingJob = {
$keys = [string[]]$syncdFsItemEventHashT.psbase.Keys
foreach ($key in $keys) {
$fsEvent = $syncdFsItemEventHashT[$key]
try {
# in case changetype eq DELETED or the item can't be found on the filesystem by the script -> remove the item from hashtable without any further actions.
# This affects temporary files from applications. BUT: Could also affect files with file permission issues.
if (($fsEvent.ChangeType -eq [System.IO.WatcherChangeTypes]::Deleted) -or (! (Test-Path -LiteralPath $fsEvent.FullPath)) ) {
$syncdFsItemEventHashT.Remove($key )
Write-Host ("==> Item '$key' with changetype '$($fsEvent.ChangeType)' removed from hashtable without any further actions!") -ForegroundColor Blue
continue
}
# get filesystem object
$fsItem = Get-Item -LiteralPath $fsEvent.FullPath -Force
if ($fsItem -is [System.IO.FileInfo]) {
# file processing
try {
# Check whether the file is still locked / in use by another process
[System.IO.FileStream]$fileStream = [System.IO.File]::Open( $fsEvent.FullPath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::Read)
$fileStream.Close()
} catch [System.IO.IOException] {
Write-Host ("==> Item '$key' with changetype '$($fsEvent.ChangeType)' is still in use and can't be read!") -ForegroundColor Yellow
continue
}
} elseIf ($fsItem -is [System.IO.DirectoryInfo]) {
# directory processing
}
$syncdFsItemEventHashT.Remove($key )
Write-Host ("==> Item '$key' with changetype '$($fsEvent.ChangeType)' has been processed and removed from hashtable.") -ForegroundColor Blue
} catch {
Write-Host ($_ | Format-List * | Out-String ) -ForegroundColor red
}
}
}
[void] (Register-ObjectEvent -InputObject $fileSystemWatcher -EventName 'Created' -SourceIdentifier 'FSCreated' -Action $fileSystemWatcherAction)
[void] (Register-ObjectEvent -InputObject $fileSystemWatcher -EventName 'Changed' -SourceIdentifier 'FSChanged' -Action $fileSystemWatcherAction)
[void] (Register-ObjectEvent -InputObject $fileSystemWatcher -EventName 'Renamed' -SourceIdentifier 'FSRenamed' -Action $fileSystemWatcherAction)
[void] (Register-ObjectEvent -InputObject $fileSystemWatcher -EventName 'Deleted' -SourceIdentifier 'FSDeleted' -Action $fileSystemWatcherAction)
Write-Host "Watching for changes in '$fileSystemWatcherDirPath'.`r`nPress CTRL+C to exit!"
try {
do {
Wait-Event -Timeout 1
if ($syncdFsItemEventHashT.Count -gt 0) {
Write-Host "`r`n"
Write-Host ('-' * 50) -ForegroundColor Green
Write-Host "Collected events in hashtable queue:" -ForegroundColor Green
$syncdFsItemEventHashT.Values | Format-Table | Out-String
}
# Process hashtable items and do something with them (like copying, ..)
.$fSItemEventProcessingJob
# Garbage collector
[GC]::Collect()
} while ($true)
} finally {
# unregister
Unregister-Event -SourceIdentifier 'FSChanged'
Unregister-Event -SourceIdentifier 'FSCreated'
Unregister-Event -SourceIdentifier 'FSDeleted'
Unregister-Event -SourceIdentifier 'FSRenamed'
# dispose
$FileSystemWatcher.Dispose()
Write-Host "`r`nEvent Handler removed."
}
发布于 2020-06-13 00:48:55
您需要构建一个测试,以查看文件是否被锁定(仍在复制)。为此,您可以使用以下函数:
function Test-LockedFile {
param (
[parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('FullName', 'FilePath')]
[ValidateScript({Test-Path $_ -PathType Leaf})]
[string]$Path
)
$file = [System.IO.FileInfo]::new($Path)
# old PowerShell versions use:
# $file = New-Object System.IO.FileInfo $Path
try {
$stream = $file.Open([System.IO.FileMode]::Open,
[System.IO.FileAccess]::ReadWrite,
[System.IO.FileShare]::None)
if ($stream) { $stream.Close() }
return $false
}
catch {
return $true
}
}
如果在当前代码之上的某个位置设置了该功能,则可以:
# File Checks
while (Test-LockedFile $path) {
Start-Sleep -Seconds 1
}
# Move File
Move-Item $path -Destination $destinationPath -Verbose
https://stackoverflow.com/questions/62350872
复制相似问题