2010-07-10 21 views
5

我正在寫一些Perl,它需要在Windows Media Center上記錄電視節目,並根據特定標準移動/重命名/刪除它們。確定一個文件是否在Windows的Perl中使用

由於Perl運行相當頻繁,我想幹淨地確定文件是否在使用中(換句話說,該節目正在被錄製過程中),所以我可以避免對它做任何事情。

我現在的方法查看文件的狀態(使用「STAT」),並在5秒後,再進行比較,如下所示:

sub file_in_use 
{ 
    my $file = shift; 

    my @before = stat($file); 
    sleep 5; 
    my @after = stat($file); 

    return 0 if ($before ~~ $after); 
    return 1; 
} 

看來工作,但我Concious酒店有這可能是一個更好和更乾淨的方式來做到這一點。

你能提供建議嗎?

+0

這是一個很好的計算策略它和我不相信你會發現許多選擇......另一種方式是通過閱讀應用程序的pid和移動文件,一旦pid已經關閉... – Prix 2010-07-10 17:45:36

+1

從Prix(我認爲這是重要的點):*如果文件全時使用並且未發佈,則不能對文件執行移動[或刪除],因爲它會產生錯誤... *。 (根據不同的文件模式設置,副本可能工作)。即使採用stat方法,您也必須*仍然*處理FS場景並僅將'file_in_use'用作'提示'(儘管潛在的競爭條件可能永遠不會實現這裏)。 – 2010-07-10 18:44:29

+0

@pst真,這就是爲什麼我認爲移動是一個很好的方式去...因爲如果文件仍然鎖定它將返回0或告訴你一個錯誤取決於你如何編碼它,你可以繼續嘗試,直到它被釋放或如此... – Prix 2010-07-10 19:06:31

回答

8

如果記錄進程鎖定文件,您可以嘗試以讀寫模式打開它,並通過ERROR_SHARING_VIOLATION作爲GetLastError(通過Perl的$^E特殊變量訪問)查看它是否失敗。

例如:

#! /usr/bin/perl 

use warnings; 
use strict; 

sub usage { "Usage: $0 file ..\n" } 

die usage unless @ARGV; 

foreach my $path (@ARGV) { 
    print "$path: "; 

    if (open my $fh, "+<", $path) { 
    print "available\n"; 
    close $fh; 
    } 
    else { 
    print $^E == 0x20 ? "in use by another process\n" : "$!\n"; 
    } 
} 

Dir100526Lt.pdf開放由的Adobe閱讀器輸出示例:

C:\Users\Greg\Downloads>check-lock.pl Dir100526Lt.pdf setup.exe 
Dir100526Lt.pdf: in use by another process 
setup.exe: available

要知道,任何時候你第一次測試一個條件,然後再採取行動基礎上的結果那個測試,你正在創建一個race condition。看來,這可能會咬你在應用程序中最糟糕的是在下面的倒黴序列:

  1. 測試可用性如上
  2. 答案視頻:可用!
  3. 在此期間,記錄啓動和鎖定的視頻
  4. 回到你的計劃,你嘗試移動視頻,但它無法與共享衝突
+0

完美!非常感謝你。關於競爭條件的好處 - 我希望這一點,一旦錄製完成,應該沒有理由再次啓動它。 – Richard 2010-07-10 20:34:58

+0

爲你的cookie我喜歡那個特殊的變量......只是一個簡單的問題,如果他知道他需要檢查的文件,並檢查它是否在當時可用,並馬上將其鎖定,直到另一個應用程序可以得到它爲止需要幾毫秒持有它,所以這將是非常非常非常難以發生的不是? – Prix 2010-07-10 22:30:36

+1

@Prix計算機需要很長的時間。不太可能意味着它有時會發生,而這些錯誤往往難以調試。誠然,在這種情況下,這可能不值得大驚小怪,但對我們來說,訓練自己能夠發現同步性裂縫是很好的。而不是檢查可用性,然後鎖定,直接獲取鎖。如果有其他人擁有它,系統會盡快將它提供給您。否則,你知道你已經擁有了它,並且它不會被其他任何人看到。 – 2010-07-10 22:58:49

1

唯一的改進,我建議是stat所有一次的文件,所以你只需要5秒入睡,而不是睡5秒,每個文件一次:

my (%before, %after); 
foreach my $file (@files_that_might_be_in_use) { 
    $before{$file} = [ stat $file ]; 
} 
sleep 5; 
foreach my $file (@files_that_might_be_in_use) { 
    $after{$file} = [ stat $file ]; 

    if ($before{$file} ~~ $after{$file}) { 
     # file is not in use ... 
    } else { 
     # file is in use ... 
    } 
} 
相關問題