使用 try 块测试文件是否在 powershell 中被锁定
Using a try block to test if a file is locked in powershell
我想知道使用 try 块来测试文件是否被锁定是否是一种错误的形式。这是背景。
我需要将应用程序的文本输出同时发送到两台串行打印机。我的解决方案是使用 MportMon 和 Powershell 脚本。它应该工作的方式是应用程序默认打印到 MportMon 虚拟打印机端口,它实际上在 "dropbox" 文件夹中创建一个唯一命名的文件。 powershell 脚本使用 filesystemwatcher 来监视文件夹,当创建新文件时,它会获取文本并将其推出两个串行打印机,然后删除文件,以免填满文件夹。尝试从虚拟打印机创建的文件中读取文本时遇到问题。我发现由于文件仍处于锁定状态而出现错误。为了解决这个问题,我使用了 FSM 来实现逻辑,而不是每次尝试从文件中获取内容之前检查锁,我使用了一个 try 块来尝试从文件中读取内容,如果失败, catch 块只是重申 FSM 所处的状态,并重复该过程直到成功。它似乎工作正常,但我在某处读到它的不良做法。这种方法有没有危险,或者安全可靠?下面是我的代码。
$fsw = New-Object system.io.filesystemwatcher
$q = New-Object system.collections.queue
$path = "c:\DropBox"
$fsw.path = $path
$state = "waitforQ"
[string]$tempPath = $null
Register-ObjectEvent -InputObject $fsw -EventName created -Action {
$q.enqueue( $event.sourceeventargs.fullpath )
}
while($true) {
switch($state)
{
"waitforQ" {
echo "waitforQ"
if ($q.count -gt 0 ) {$state = "retrievefromQ"}
}
"retrievefromQ" {
echo "retrievefromQ"
$tempPath = $q.dequeue()
$state = "servicefile"
}
"servicefile" {
echo " in servicefile "
try
{
$text = Get-Content -ErrorAction stop $tempPath
#echo "in try"
$text | out-printer db1
$text | out-printer db2
echo " $text "
$state = "waitforQ"
rm $tempPath
}
catch
{
#echo "in catch"
$state = "servicefile"
}
}
Default { $state = "waitforQ" }
}
}
我不会说测试文件以查看它是否被锁定是不好的做法,但它不如检查其他进程使用的句柄那么干净。我个人会像您一样测试该文件,但我调整了几个部分以使其成为 safer/better。
- 那个 switch 语句看起来很复杂(对我来说),我会用一个简单的 if 测试来代替它。 "If files in queue, proceed, if not, wait".
- 您需要放慢速度.. 您将尝试在文件锁定时尽可能多地读取该文件。这是一种资源浪费,因为当前应用程序需要一些时间才能将其释放并将数据保存到 HDD。添加一些停顿。您不会注意到它们,但您的 CPU 会爱上它们。当队列中没有文件时也是如此。
- 您可能会受益于添加超时,例如最多 50 次尝试读取文件,以避免脚本在某个特定文件从未被释放时卡住。
尝试:
$fsw = New-Object system.io.filesystemwatcher
$q = New-Object system.collections.queue
$path = "c:\DropBox"
$fsw.path = $path
$MaxTries = 50 #50times * 0,2s sleep = 10sec timeout
[string]$tempPath = $null
Register-ObjectEvent -InputObject $fsw -EventName created -Action {
$q.enqueue( $event.sourceeventargs.fullpath )
}
while($true) {
if($q.Count -gt 0) {
#Get next file in queue
$tempPath = $q.dequeue()
#Read file
$text = $null
$i = 0
while($text -eq $null) {
#If locked, wait and try again
try {
$text = Get-Content -Path $tempPath -ErrorAction Stop
} catch {
$i++
if($i -eq $MaxTries) {
#Max attempts reached. Stops script
Write-Error -Message "Script is stuck on locked file '$tempPath'" -ErrorAction Stop
} else {
#Wait
Start-Sleep -Milliseconds 200
}
}
}
#Print file
$text | Out-Printer db1
$text | Out-Printer db2
echo " $text "
#Remove temp-file
Remove-Item $tempPath
}
#Relax..
Start-Sleep -Milliseconds 500
}
我想知道使用 try 块来测试文件是否被锁定是否是一种错误的形式。这是背景。 我需要将应用程序的文本输出同时发送到两台串行打印机。我的解决方案是使用 MportMon 和 Powershell 脚本。它应该工作的方式是应用程序默认打印到 MportMon 虚拟打印机端口,它实际上在 "dropbox" 文件夹中创建一个唯一命名的文件。 powershell 脚本使用 filesystemwatcher 来监视文件夹,当创建新文件时,它会获取文本并将其推出两个串行打印机,然后删除文件,以免填满文件夹。尝试从虚拟打印机创建的文件中读取文本时遇到问题。我发现由于文件仍处于锁定状态而出现错误。为了解决这个问题,我使用了 FSM 来实现逻辑,而不是每次尝试从文件中获取内容之前检查锁,我使用了一个 try 块来尝试从文件中读取内容,如果失败, catch 块只是重申 FSM 所处的状态,并重复该过程直到成功。它似乎工作正常,但我在某处读到它的不良做法。这种方法有没有危险,或者安全可靠?下面是我的代码。
$fsw = New-Object system.io.filesystemwatcher
$q = New-Object system.collections.queue
$path = "c:\DropBox"
$fsw.path = $path
$state = "waitforQ"
[string]$tempPath = $null
Register-ObjectEvent -InputObject $fsw -EventName created -Action {
$q.enqueue( $event.sourceeventargs.fullpath )
}
while($true) {
switch($state)
{
"waitforQ" {
echo "waitforQ"
if ($q.count -gt 0 ) {$state = "retrievefromQ"}
}
"retrievefromQ" {
echo "retrievefromQ"
$tempPath = $q.dequeue()
$state = "servicefile"
}
"servicefile" {
echo " in servicefile "
try
{
$text = Get-Content -ErrorAction stop $tempPath
#echo "in try"
$text | out-printer db1
$text | out-printer db2
echo " $text "
$state = "waitforQ"
rm $tempPath
}
catch
{
#echo "in catch"
$state = "servicefile"
}
}
Default { $state = "waitforQ" }
}
}
我不会说测试文件以查看它是否被锁定是不好的做法,但它不如检查其他进程使用的句柄那么干净。我个人会像您一样测试该文件,但我调整了几个部分以使其成为 safer/better。
- 那个 switch 语句看起来很复杂(对我来说),我会用一个简单的 if 测试来代替它。 "If files in queue, proceed, if not, wait".
- 您需要放慢速度.. 您将尝试在文件锁定时尽可能多地读取该文件。这是一种资源浪费,因为当前应用程序需要一些时间才能将其释放并将数据保存到 HDD。添加一些停顿。您不会注意到它们,但您的 CPU 会爱上它们。当队列中没有文件时也是如此。
- 您可能会受益于添加超时,例如最多 50 次尝试读取文件,以避免脚本在某个特定文件从未被释放时卡住。
尝试:
$fsw = New-Object system.io.filesystemwatcher
$q = New-Object system.collections.queue
$path = "c:\DropBox"
$fsw.path = $path
$MaxTries = 50 #50times * 0,2s sleep = 10sec timeout
[string]$tempPath = $null
Register-ObjectEvent -InputObject $fsw -EventName created -Action {
$q.enqueue( $event.sourceeventargs.fullpath )
}
while($true) {
if($q.Count -gt 0) {
#Get next file in queue
$tempPath = $q.dequeue()
#Read file
$text = $null
$i = 0
while($text -eq $null) {
#If locked, wait and try again
try {
$text = Get-Content -Path $tempPath -ErrorAction Stop
} catch {
$i++
if($i -eq $MaxTries) {
#Max attempts reached. Stops script
Write-Error -Message "Script is stuck on locked file '$tempPath'" -ErrorAction Stop
} else {
#Wait
Start-Sleep -Milliseconds 200
}
}
}
#Print file
$text | Out-Printer db1
$text | Out-Printer db2
echo " $text "
#Remove temp-file
Remove-Item $tempPath
}
#Relax..
Start-Sleep -Milliseconds 500
}