Determine if a file is used in Perl on Windows

I am writing Perl, which accepts television shows recorded in the Windows Media Center, and moves / renames / deletes them depending on certain criteria.

Since Perl works quite often, I would like to clearly determine if the file is being used (in other words, the show is in the process of writing), so I can avoid anything with it.

My current method looks at the state of the file (using "stat") and compares it again after 5 seconds, for example:

sub file_in_use { my $file = shift; my @before = stat($file); sleep 5; my @after = stat($file); return 0 if ($before ~~ $after); return 1; } 

This seems to work, but I understand that there is probably a better and cleaner way to do this.

Could you advise?

+5
source share
2 answers

If the write process locks the file, you can try to open it in read-write mode and see if it works with ERROR_SHARING_VIOLATION as GetLastError (access via the special variable Perl $^E ).

For instance:

 #! /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"; } } 

Sample output from Dir100526Lt.pdf opened by an Adobe reader:

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

Keep in mind that at any time when you first check the status and then later act on the basis of the result of this test, you create a race condition. It seems that the worst thing that can bite you in your application is the following unsuccessful sequence:

  • check video for availability as above
  • Answer: available!
  • meanwhile, the recorder starts and blocks the video
  • in your program, you are trying to move the video, but it does not work with violation of the exchange.
+8
source

The only improvement I would suggest is stat all your files at once, so you only need to sleep for 5 seconds once instead of sleeping 5 seconds for each file:

 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 ... } } 
+1
source

Source: https://habr.com/ru/post/972248/


All Articles