Я пишу некоторый Perl, который берет телепередачи, записанные на Windows Media Center, и перемещает/переименовывает/удаляет их в зависимости от определенных критериев.
Так как Perl работает справедливо часто, я хотел бы чисто определить, используется ли файл (другими словами, шоу находится в процессе того, чтобы быть зарегистрированным), таким образом, я могу постараться не делать что-либо с ним.
Мой существующий метод смотрит на состояние файла (использующий "статистику") и сравнивает его снова после 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;
}
Это, кажется, работает, но я сознателен, что существует, вероятно, лучший и более чистый способ сделать это.
Можно ли советовать?
Если процесс записи блокирует файл, вы можете попытаться открыть его в режиме чтения-записи и посмотреть, не завершится ли он с помощью 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
Имейте в виду, что каждый раз, когда вы сначала проверяете условие, а затем действуете на его основе test, вы создаете состояние гонки .Похоже, что худшее, что это может вас укусить в вашем приложении, находится в следующей неудачной последовательности:
Единственное улучшение, которое я бы предложил, - это 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 ...
}
}