Python – ¿Cómo verificar si un archivo es usado por otra aplicación?

Quiero abrir un archivo que se escribe periódicamente en otra aplicación. Esta aplicación no puede ser modificada. Por lo tanto, me gustaría abrir el archivo solo cuando sé que no ha sido escrito por otra aplicación.

¿Hay una forma pythonica de hacer esto? De lo contrario, ¿cómo logro esto en Unix y Windows?

Edición : Voy a tratar de aclarar. ¿Hay alguna forma de verificar si otra aplicación ha abierto el archivo actual?

Me gustaría comenzar con esta pregunta. Si esas otras aplicaciones de lectura / escritura son irrelevantes por ahora.

Me doy cuenta de que probablemente sea dependiente del sistema operativo, por lo que es posible que esto no esté relacionado con Python en este momento.

¿Su script de Python desea abrir el archivo para escribir o para leer? ¿La aplicación heredada está abriendo y cerrando el archivo entre escrituras o lo mantiene abierto?

Es extremadamente importante que entendamos lo que hace la aplicación heredada y lo que su script de python está intentando lograr.

Esta área de funcionalidad depende en gran medida del sistema operativo, y el hecho de que no tenga control sobre la aplicación heredada solo dificulta las cosas, desafortunadamente. Si existe una forma pythonica o no pirónica de hacer esto, probablemente sea la menor de sus preocupaciones: la pregunta difícil será si lo que está tratando de lograr será posible.


ACTUALIZAR

De acuerdo, sabiendo (por tu comentario) que:

La aplicación heredada abre y cierra el archivo cada X minutos, pero no quiero asumir que en t = t_0 + n * X + eps ya cerró el archivo.

entonces se cambian los parámetros del problema. En realidad, se puede hacer de forma independiente del sistema operativo a partir de algunas suposiciones, o como una combinación de técnicas dependientes e independientes del sistema operativo. 🙂

  1. Modo independiente del sistema operativo : si es seguro asumir que la aplicación heredada mantiene el archivo abierto durante, como mucho, una cantidad conocida de tiempo, digamos T segundos (por ejemplo, abre el archivo, realiza una escritura, luego cierra el archivo) y vuelve a lo abre más o menos cada X segundos, donde X es mayor que 2 * T
    • stat el archivo
    • resta la hora de modificación del archivo a partir de now() , produciendo D
    • si T <= D < X , abra el archivo y haga lo que necesite con él
    • Esto puede ser lo suficientemente seguro para su aplicación . La seguridad aumenta a medida que T / X disminuye. En * nix, es posible que tenga que revisar dos /etc/ntpd.conf para determinar la /etc/ntpd.conf adecuada de /etc/ntpd.conf de tiempo en comparación con la configuración de giro (vea tinker). Para Windows ver MSDN
  2. Windows : además (o en lugar de) el método independiente del sistema operativo anterior, puede intentar usar:
    • compartir (bloquear): esto supone que el progtwig heredado también abre el archivo en modo compartido (generalmente el predeterminado en las aplicaciones de Windows); además, si su aplicación adquiere el locking justo cuando la aplicación heredada está intentando lo mismo (condición de carrera), la aplicación heredada fallará.
      • Esto es extremadamente intrusivo y propenso a errores. A menos que tanto la aplicación nueva como la heredada necesiten acceso sincronizado para escribir en el mismo archivo y usted esté dispuesto a manejar la posibilidad de que se le deniegue la apertura de la aplicación heredada, no use este método.
    • intentar averiguar qué archivos están abiertos en la aplicación heredada, usando las mismas técnicas que ProcessExplorer (el equivalente de * nix’s lsof )
      • Eres incluso más vulnerable a las condiciones de carrera que la técnica independiente del sistema operativo.
  3. Linux / etc. : además (o en lugar de) el método independiente del SO anterior, puede intentar usar la misma técnica que lsof o, en algunos sistemas, simplemente verifique qué archivo del enlace simbólico /proc//fd/ apunta a
    • Eres incluso más vulnerable a las condiciones de carrera que la técnica independiente del sistema operativo.
    • es muy poco probable que la aplicación heredada use el locking, pero si lo es, el locking no es una opción real a menos que la aplicación heredada pueda manejar un archivo bloqueado con gracia (bloqueando, no fallando) y si su propia aplicación puede garantizar que el archivo no permanecerá bloqueado, bloqueando la aplicación heredada durante períodos prolongados de tiempo).

ACTUALIZACIÓN 2

Si está a favor de “verificar si la aplicación heredada tiene el archivo abierto” (enfoque intrusivo propenso a las condiciones de la carrera), puede resolver dicha condición de la carrera mediante:

  1. comprobando si la aplicación heredada tiene el archivo abierto (a la lsof o ProcessExplorer )
  2. suspendiendo el proceso de solicitud legado
  3. repitiendo la verificación en el paso 1 para confirmar que la aplicación heredada no abrió el archivo entre los pasos 1 y 2; retrasar y reiniciar en el paso 1 si es así, de lo contrario, continúe con el paso 4
  4. hacer su negocio en el archivo – lo ideal es simplemente cambiarle el nombre para un procesamiento posterior e independiente con el fin de mantener la aplicación heredada suspendida por un tiempo mínimo
  5. reanudar el proceso de solicitud legado

Unix no tiene locking de archivos por defecto. La mejor sugerencia que tengo para un entorno Unix sería mirar las fonts del comando lsof. Tiene un conocimiento profundo sobre qué proceso tiene qué archivos se abren. Podrías usar eso como la base de tu solución. Aquí están las fonts de Ubuntu para lsof.

Una cosa que he hecho es que Python cambie temporalmente el nombre del archivo. Si podemos cambiarle el nombre, no hay otro proceso que lo esté utilizando. Sólo he probado esto en Windows.