简体   繁体   English

使用try块测试文件是否在Powershell中被锁定

[英]Using a try block to test if a file is locked in powershell

I want to know if its bad form to use try blocks to test if a file is locked. 我想知道使用try块来测试文件是否被锁定的错误形式。 Here's the background. 这是背景。 I need to send text output of an application to two serial printers simultaneously. 我需要将应用程序的文本输出同时发送到两台串行打印机。 My solution was to use MportMon, and a Powershell script. 我的解决方案是使用MportMon和Powershell脚本。 The way it's supposed to work is the application default prints to the MportMon virtual printer port, which actually makes a uniquely named file in a "dropbox" folder. 它应该起作用的方式是应用程序默认打印到MportMon虚拟打印机端口,该端口实际上在“ dropbox”文件夹中创建一个唯一命名的文件。 The powershell script uses a filesystemwatcher to monitor the folder and when a new file is created, it takes the textual content and pushes it out two serial printers, then deletes the file, so as not to fill up the folder. Powershell脚本使用filesystemwatcher来监视文件夹,并且在创建新文件时,它将获取文本内容并将其推出两台串行打印机,然后删除该文件,以免填满该文件夹。 I was having a problem when trying to read the text from the file that the virtual printer created. 尝试从虚拟打印机创建的文件中读取文本时遇到问题。 I found that I was getting errors becasue the file was still locked. 我发现由于文件仍被锁定而出现错误。 To fixed the problem, I used a FSM to impliment the logic and instead of checking for a lock everytime before attempting to get the content from the file, I used a try block that attempts to read content from the file, if it fails, the catch block just reaffirms the state that the FSM is in, and the process is repeated until successful. 为了解决该问题,我使用了FSM来实现逻辑,而不是每次尝试从文件中获取内容之前都不检查锁,而是使用try块尝试从文件中读取内容,如果失败,则尝试从文件中读取内容。 catch块只是重申了FSM所在的状态,并且重复该过程直到成功。 It seems to work fine, but I've read somewhere that its bad practice. 看来工作正常,但我在某处读到它的不良做法。 Is there any danger in this method, or is it safe and reliable? 此方法是否存在危险,还是安全可靠? Below is my code. 下面是我的代码。

$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"  }
    }
    }

I wouldn't say it's bad practice to test a file to see if it's locked, but it's not as clean as checking the handles used by other processes. 我不会说测试文件以查看是否已锁定是不好的做法,但是它不如检查其他进程使用的句柄那么干净。 Personally I'd test the file like you do, but I adjust a few parts to make it safer/better. 我个人会像您一样测试文件,但会进行一些调整以使其更安全/更好。

  • That switch-statement looks way to complicated (for me), I'd replace it with a simple if-test. 该切换语句看起来很复杂(对我而言),我将其替换为简单的if-test。 "If files in queue, proceed, if not, wait". “如果文件在队列中,请继续,否则,请等待”。
  • You need to slow down.. You will try to read the file as many times as possible while it's locked. 您需要放慢速度。.在锁定文件时,您将尝试尽可能多地读取该文件。 This is a waste of resources since it will take some time for the current application to let it go and save the data to a HDD. 这是浪费资源,因为当前应用程序要花一些时间才能将其保存并将数据保存到HDD。 Add some pauses. 添加一些暂停。 You won't notice them, but your CPU will love them. 您不会注意到它们,但是您的CPU会喜欢它们。 The same applies when there are no files in the queue. 当队列中没有文件时,也是如此。
  • You might benefit from adding a timeout, like max 50 attempts to read the file, to avoid the script getting stuck if one specific file is never released. 您可能会受益于添加超时(例如最多50次尝试读取文件),以避免在从未释放一个特定文件的情况下脚本卡住的情况。

Try: 尝试:

$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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM