2010-07-10 17 views
5

Estoy escribiendo algunos Perl que toma programas de TV grabados en Windows Media Center y los mueve/cambia el nombre/los elimina dependiendo de ciertos criterios.Determinar si un archivo está en uso en Perl en Windows

Dado que Perl se ejecuta con bastante frecuencia, me gustaría determinar claramente si el archivo está en uso o no (en otras palabras, el programa está en proceso de grabación) para evitar hacer algo con él.

Mi método actual se ve en el estado de un archivo (usando "stat") y lo compara de nuevo después de 5 segundos, así:

sub file_in_use 
{ 
    my $file = shift; 

    my @before = stat($file); 
    sleep 5; 
    my @after = stat($file); 

    return 0 if ($before ~~ $after); 
    return 1; 
} 

Parece que funciona, pero soy consciente de que hay es probablemente una forma mejor y más limpia de hacer esto.

¿Puede avisarnos?

+0

Este es un buen approch a la misma y No creo que encuentre muchas opciones alrededor ... otra forma de hacerlo sería leyendo la aplicación pid y mover los archivos una vez que el pid se haya apagado ... – Prix

+1

de Prix (creo que es tan importante señalar out): * Si el archivo se está utilizando a tiempo completo y no se ha liberado, no puede realizar un movimiento [o eliminar] en el archivo, ya que producirá un error ... *. (Una copia puede funcionar dependiendo de las distintas configuraciones de modo de archivo). Incluso con el método stat, debes * todavía * manejar el escenario FS y usar el 'file_in_use' solo como 'pista' (aunque las posibles condiciones de carrera pueden nunca materializarse) aquí). –

+0

@pst Cierto, por eso creo que mover es una buena forma de hacerlo ... ya que si el archivo todavía está bloqueado, devolverá 0 o le dirá un error dependiendo de cómo lo codifique y puede seguir intentándolo hasta se lanza más o menos ... – Prix

Respuesta

8

Si la grabación proceso bloquea el archivo, puede intentar abrirlo en modo lectura-escritura y ver si falla con ERROR_SHARING_VIOLATION como GetLastError (se accede a través de la variable especial $^E de Perl).

Por ejemplo:

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

Salida de ejemplo con Dir100526Lt.pdf abierta por el lector de Adobe:

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

Tenga en cuenta que cada vez que primera prueba una condición y luego actuar en función del resultado de esa prueba, estás creando un race condition. Parece que lo peor que esto podría morder en su aplicación es en la siguiente secuencia de mala suerte:

  1. prueba un video disponibilidad que el anterior
  2. respuesta: disponible!
  3. , mientras tanto, una grabadora pone en marcha y bloquea el video
  4. atrás en su programa, intenta mover el video, pero falla con un intercambio de violación
+0

¡Perfecto! Muchas gracias. Buen punto sobre la condición de la carrera: como tal, espero que, una vez que la grabación haya terminado, no haya ninguna razón para que vuelva a comenzar. – Richard

+0

cookie para ti Me gusta esa variable especial ... solo una pregunta rápida, si conoce el archivo que necesita verificar y verifica que esté disponible en ese momento y lo bloquea de inmediato sería como milisegundos hasta que otra aplicación pueda obtenerlo una bodega de modo que sería muy, muy, muy difícil pasar, ¿no? – Prix

+1

@Prix Un milisegundo es mucho tiempo para una computadora. Poco probable significa que * sucederá * a veces, y este tipo de errores suelen ser difíciles de depurar. De acuerdo, en este caso, probablemente no valga la pena el alboroto, pero es bueno para nosotros entrenarnos para detectar grietas de sincronización. En lugar de verificar la disponibilidad y luego bloquearla, adquiera la cerradura de inmediato. Si alguien más lo tiene, el sistema se lo dará tan pronto como esté disponible. De lo contrario, sabrá que lo tiene, y no aparecerá disponible para nadie más. –

1

La única mejora que sugeriría es stat todos sus archivos a la vez, por lo que sólo necesita dormir durante 5 segundos una vez en lugar de dormir 5 segundos para cada archivo:

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 ... 
    } 
} 
Cuestiones relacionadas