我正在编写一些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;
}
它似乎有效,但我很有意思,可能有一种更好,更清洁的方法。
你能告诉我吗?
答案 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";
}
}
Adobe读者打开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 :(得分: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
类型字符串。