texto read open manejo leer files como archivos archivo perl file flush io-buffering

read - ¿Cómo descargo un archivo en Perl?



perl read file line by line (9)

Tengo un script Perl que agrega una nueva línea al archivo existente cada 3 segundos. Además, hay una aplicación C ++ que lee desde ese archivo.

El problema es que la aplicación comienza a leer el archivo después de que se realiza la secuencia de comandos y se cierra el identificador de archivo. Para evitar esto, quiero limpiar después de cada línea agregada, pero soy nuevo en Perl y no sé cómo hacerlo.


Aquí está la respuesta, la respuesta real.

Deje de mantener un identificador de archivo abierto para este archivo durante la vida del proceso.

COMIENCE a abstraer su operación de agregar archivo a un sub que abra el archivo en modo de aplicación, lo escriba, lo cierre.

#appends a new line to the existing file sub append_new_line{ my $linedata = shift; open my $fh, ''>>'', $fnm or die $!; # $fnm is file-lexical or something print $fh $linedata,"/n"; # flavor to taste close $fh; }

el proceso que observa el archivo encontrará un archivo cerrado que se modifica cada vez que se llama a la función.


Desde ''man perlfaq5'':

$old_fh = select(OUTPUT_HANDLE); $| = 1; select($old_fh);

Si solo desea eliminar la salida estándar, probablemente solo puede hacer:

$| = 1;

Pero consulte las Preguntas frecuentes para obtener detalles sobre un módulo que le brinda una abstracción más agradable de usar, como IO::Handle .


Hay un artículo sobre esto en PerlDoc: ¿Cómo puedo vaciar / desempacar un identificador de archivo de salida? ¿Por qué debo hacer esto?

Dos soluciones:

  • Desempañar el manejador de archivos de salida con: $|
  • Llame al método de autoflush si está utilizando IO::Handle o una de sus subclases.

Para vaciar automáticamente la salida, puede configurar autoflush / $| como lo describieron los demás antes de enviar al manejador de archivos .

Si ya ha realizado la salida al identificador de archivo y necesita asegurarse de que llegue al archivo físico, debe utilizar los métodos de flush y sync IO :: Handle.


TL / DR: use IO::Handle y el método de flush , por ejemplo:

use IO::Handle; $myfile->flush();

Primero, debes decidir qué tan "enrojecido" lo quieres. Puede haber bastantes capas de almacenamiento en búfer:

  • El buffer interno de Perl en el manejador de archivos. Otros programas no pueden ver datos hasta que queda este búfer.

  • Búfer a nivel de sistema de archivos de bloques de archivos "sucios". Otros programas aún pueden ver estos cambios, parecen "escritos", pero se perderán si se bloquea el sistema operativo o la máquina.

  • Almacenamiento en búfer de escritura a nivel de disco de las escrituras. El sistema operativo cree que estos están escritos en el disco, pero en realidad el disco solo los almacena en la memoria volátil de la unidad. Si el sistema operativo falla, los datos no se perderán, pero si falla la alimentación, podría ser a menos que el disco pueda escribirlos primero. Este es un gran problema con los SSD de consumo baratos.

Se complica aún más cuando se involucran SAN, sistemas de archivos remotos, controladores RAID, etc. Si está escribiendo a través de tuberías, también hay que considerar el búfer de tubería.

Si solo desea vaciar el búfer de Perl, puede close el archivo, print una cadena que contenga "/n" (ya que parece que Perl se vacía en las nuevas líneas), o usar el método de flush IO::Handle .

También puede, por el perl faq usar binmode o jugar con $| Para hacer que el archivo se maneje sin búfer. Esto no es lo mismo que vaciar un controlador almacenado en búfer, ya que poner en cola un montón de escrituras almacenadas en búfer y luego hacer un solo lavado tiene un costo de rendimiento mucho menor que escribir en un controlador no almacenado.

Si desea vaciar el búfer de escritura del sistema de archivos, debe usar una llamada del sistema como fsync() , abrir su archivo en el modo O_DATASYNC o usar una de las muchas otras opciones. Es muy complicado, como lo demuestra el hecho de que PostgreSQL tiene su propia herramienta solo para probar los métodos de sincronización de archivos .

Si desea asegurarse de que realmente, de verdad, honestamente en el disco duro en almacenamiento permanente, debe descargarlo en el sistema de archivos de su programa. También debe configurar el disco duro / SSD / controlador RAID / SAN / lo que sea para que se vacíe realmente cuando el sistema operativo lo solicite. Esto puede ser sorprendentemente complicado de hacer y es bastante específico del sistema operativo / hardware. se recomienda encarecidamente realizar pruebas "plug-pull" para asegurarte de que realmente lo hiciste bien.


Todas las soluciones que sugieren la configuración de autoflush ignoran el hecho básico de que la mayoría de los sistemas operativos modernos están almacenando en búfer la E / S, independientemente de lo que esté haciendo Perl.

La única posibilidad de forzar el compromiso de los datos en el disco es cerrar el archivo.

Estoy atrapado con el mismo dilema atm en el que tenemos un problema con la rotación del registro que se está escribiendo.


Tratar:

use IO::Handle; $fh->autoflush;

Esto fue publicado en realidad como una forma de auto-lavado en una de mis primeras preguntas , que preguntaba acerca de la mala manera universalmente aceptada de lograr esto :-)


Tuve el mismo problema con la única diferencia de escribir el mismo archivo una y otra vez con nuevo contenido. Esta asociación de "$ | = 1" y autoflush funcionó para mí:

open (MYFILE, ''>'', ''/internet/web-sites/trot/templates/xml_queries/test.xml''); $| = 1; # Before writing! print MYFILE "$thisCardReadingContentTemplate/n/n"; close (MYFILE); MYFILE->autoflush(1); # After writing!

La mejor de las suertes. H


Un enfoque alternativo sería utilizar una tubería con nombre entre su script Perl y el programa C ++, en lugar del archivo que está utilizando actualmente.