确定Windows上的Perl中是否正在使用文件

时间:2010-07-10 17:36:27

标签: windows perl file winapi testing

我正在编写一些Perl,它可以播放Windows Media Center上录制的电视节目,并根据特定条件移动/重命名/删除它们。

由于Perl运行频繁,我想清楚地确定文件是否正在使用(换句话说,节目正在被录制),所以我可以避免使用它。< / p>

我当前的方法查看文件的状态(使用“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;
 }

它似乎有效,但我很有意思,可能有一种更好,更清洁的方法。

你能告诉我吗?

3 个答案:

答案 0 :(得分: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";
  }
}

Adob​​e读者打开Dir100526Lt.pdf的示例输出:

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. 回到你的程序中,你试图移动视频,但是它因共享违规而失败

答案 1 :(得分: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 ... 
    }
}

答案 2 :(得分:0)

存在一个Windows API,它将列出保持文件打开的进程数。它是Restart Manager(Rststmgr.dll)。基于artical How do I find out which process has a file open?,在Win32 :: API的帮助下,您可以在Perl程序中转换程序,该程序告诉您打开文件的进程数,甚至列出进程ID。

每个测试应该是RmStartSession,RmRegisterResources,RmGetList,RmEndSession的序列。使用encode("UTF-16LE",$filename)制作CWSTR类型字符串。