2010-12-27 30 views
17

Tengo una secuencia de comandos 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.¿Cómo descargo un archivo en Perl?

El problema es que la aplicación comienza a leer el archivo una vez que se ha realizado la secuencia de comandos y se cierra el identificador de archivo. Para evitar esto, deseo sonrojar después de agregar cada línea, pero soy nuevo para Perl y no sé cómo hacerlo.

+0

En Perl "básico" no hay función de vaciado, pero si Usted llama a 'binmode $ filehandle' establecerá el formato': raw' y (como un efecto secundario) hará un color. Funciona bien De todos modos, si está en un * x, puede crear un conducto con nombre en el sistema de archivos, y puede escribir en él directamente. – TrueY

+0

Haga que su programa C++ lea desde una tubería ('/ dev/stdin' si es lo suficientemente estúpido como para requerir un nombre de archivo) y verifique que realmente pueda leer una línea a la vez; si usa lectura almacenada en bloque, no hay nada que pueda hacer en el lado de la escritura. – reinierpost

Respuesta

25

Probar:

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

Este fue en realidad escrito como una forma de auto-lavado en an early question of mine, que preguntó por el camino malo universalmente aceptada de la consecución de este :-)

+1

Gracias. Pero esto no me ayuda. Incluso después de enjuagar después de cada línea, mi programa C++ no puede leer estas líneas, después de haber sido inscritas. Se lee solo después de que perl finaliza su trabajo. –

14

De 'hombre perlfaq5' :

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

Si lo que desea es eliminar la salida estándar, probablemente puede hacer:

$| = 1; 

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

1

para limpiar automáticamente la salida, se puede establecer autoflush/$| como se describe por otros antes de la salida al gestor de archivo.

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

-1

Tuve el mismo problema con la única diferencia de escribir el mismo archivo una y otra vez con contenido nuevo. 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! 

Best of luck. H

+3

afaik, cerrando el archivo haga el color. ¿Qué se supone que debe hacer MYFILE-> autoflush (1) aquí? – PypeBros

2

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

Solo es posible forzar el compromiso de los datos al disco cerrando el archivo.

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

+3

"La única posibilidad de forzar el compromiso de los datos en el disco es cerrando el archivo". Cerrar un archivo no lo compromete en el disco, el sistema operativo aún puede grabarlo en caché. La única forma garantizada es llamar '' fsync() 'o el equivalente de su SO al descriptor del archivo. De lo contrario, podría perderse en el bloqueo del sistema operativo o en la pérdida de energía. –

0

Un enfoque alternativo sería utilizar un named pipe entre su secuencia de comandos Perl y el programa C++, en lugar del archivo que está utilizando actualmente.

20

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

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

En primer lugar, tiene que decidir cómo "enrojecimiento" que lo desee. Puede haber bastantes capas de almacenamiento en búfer:

  • El búfer interno de Perl en el identificador de archivo. Otros programas no pueden ver datos hasta que haya dejado este búfer.

  • Almacenamiento en búfer de 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 el sistema operativo o la máquina fallan.

  • Almacenamiento en memoria intermedia del nivel de disco de las escrituras. El SO cree que están escritos en el disco, pero el disco en realidad 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 energía, es posible que el disco no pueda escribirlos primero. Este es un gran problema con los SSD de consumo baratos.

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

Si lo que desea es vaciar el búfer Perl, puede close el archivo, print una cadena que contiene "\n" (ya que parece que Perl vuelca en nuevas líneas), o use IO::Handle's flush method.

También puede, por the perl faq usar binmode o jugar con $| para hacer que el archivo se maneje sin búfer. Esto es , no es lo mismo que como enjuagar un identificador almacenado en el búfer, ya que poner en cola un montón de escrituras con búfer y luego hacer un único enrojecimiento tiene un costo de rendimiento mucho menor que escribir en un identificador sin búfer.

Si desea vaciar el búfer de escritura del sistema de escritura de archivos, debe usar una llamada al sistema como fsync(), abrir su archivo en el modo O_DATASYNC, o usar una de las muchas otras opciones. Es dolorosamente complicado, como lo demuestra el hecho de que PostgreSQL has its own tool just to test file syncing methods.

Si quiere asegurarse de que realmente, honestamente, en el disco duro en el almacenamiento permanente debe enjuagarlo en el sistema de archivos de su programa. También necesita configurar el disco duro/SSD/controlador RAID/SAN/lo que sea para que realmente se descargue cuando el sistema operativo se lo solicite. Esto puede ser sorprendentemente complicado de hacer y es bastante específico de OS/hardware. Se recomienda encarecidamente la prueba de "conectar y tirar" para asegurarse de que realmente lo hizo bien.

1

Aquí está la respuesta, la verdadera.

STOP manteniendo un archivo abierto para este archivo durante la vida del proceso.

START resumen de la operación de agregar archivo en un sub que abre el archivo en el modo de adición, lo escribe, lo cierra.

#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 de observación del archivo encontrará un archivo cerrado que se modifica cada vez que se llama a la función.

Cuestiones relacionadas