2010-07-10 73 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 ... 
    } 
} 
相关问题