Comment puis-je vider un fichier en Perl?
J'ai le script Perl qui ajoute une nouvelle ligne au fichier existant toutes les 3 secondes. De plus, il y a une application C++ qui lit à partir de ce fichier.
le problème est que l'application commence à lire le fichier après que le script soit terminé et que le traitement du fichier soit fermé. Pour éviter cela je veux tirer la chasse après chaque ligne ajoute, Mais je suis nouveau à Perl et ne sais pas comment faire cela.
9 réponses
Essaie:
use IO::Handle;
$fh->autoflush;
ceci a été en fait affiché comme une façon d'auto-flushing dans un début de question de la mienne, qui s'interrogeait sur la mauvaise façon universellement acceptée d'y parvenir : -)
TL/DR: use IO::Handle
et flush
méthode, par exemple:
use IO::Handle;
$myfile->flush();
tout d'Abord, vous devez décider combien de "flusher" vous le souhaitez. Il peut y avoir plusieurs couches de tampon:
le tampon interne de Perl sur la poignée du fichier. Les autres programmes ne peuvent pas voir les données avant d'avoir quitté ce tampon.
mise en mémoire tampon des blocs de fichiers "Sales" au niveau du système de fichiers. D'autres programmes peuvent encore voir ces changements, ils semblent "écrit", mais ils seront perdus si L'OS ou la machine s'écrase.
tampon de retour d'écriture au niveau du disque. L'OS pense que ceux-ci sont écrits sur le disque, mais le disque est en fait juste les stocker dans la mémoire volatile sur le lecteur. Si le système d'exploitation plante, les données ne seront pas perdues, mais si l'alimentation tombe en panne, cela pourrait être le cas, à moins que le disque ne puisse l'écrire en premier. C'est un gros problème avec les SSD bon marché.
cela devient encore plus compliqué quand SANs, systèmes de fichiers à distance, RAID les contrôleurs, etc s'impliquer. Si vous écrivez via des pipes, il y a aussi le tampon pipes à considérer.
Si vous voulez juste pour vider le Perl mémoire tampon, vous pouvez close
le fichier print
une chaîne contenant "\n"
(puisqu'il semble que Perl flushes sur newlines), ou utiliser IO::Handle
flush
méthode.
Vous pouvez aussi, par la faq perl utiliser binmode
ou de jouer avec $|
pour que la poignée du fichier ne soit pas froissée. C'est pas la même chose comme rincer une poignée tamponnée, depuis la mise en file d'attente d'un tas d'Écritures tamponnées, faire une seule chasse d'eau coûte beaucoup moins cher que d'écrire à une poignée non tamponnée.
si vous voulez purger le tampon d'écriture du système de fichiers, vous devez utiliser un appel système comme fsync()
, ouvrez votre fichier dans O_DATASYNC
mode, ou utiliser l'une des nombreuses autres options. C'est douloureusement compliqué, comme le prouve le fait que PostgreSQL a son propre outil juste pour tester méthodes de synchronisation des fichiers.
Si vous voulez vous assurer qu'il est vraiment, vraiment, honnêtement, sur le disque dur de stockage permanent, vous devez purger le système de fichier dans votre programme. Vous avez également besoin de configurer le disque dur/SSD/RAID controller/SAN/n'importe quoi pour vraiment tirer la chasse lorsque le système D'exploitation le demande. Cela peut être étonnamment compliqué à faire et est tout à fait spécifique OS/matériel. le test "plug-pull" est fortement recommandé pour s'assurer que vous avez bien compris.
à Partir de "l'homme perlfaq5':
$old_fh = select(OUTPUT_HANDLE);
$| = 1;
select($old_fh);
Si vous voulez juste flush stdout, vous pouvez probablement juste de faire:
$| = 1;
mais consultez la FAQ pour plus de détails sur un module qui vous donne une abstraction plus agréable à utiliser, comme IO::Handle
.
toutes les solutions suggérant la mise en place d'autoflush ne tiennent pas compte du fait que la plupart des OS modernes tamponnent les entrées/sorties des fichiers indépendamment de ce que Perl fait.
Vous seule possibilité de forcer l'engagement des données au disque est en fermant le fichier.
je suis coincé avec le même dilemme atm où nous avons un problème avec la rotation du journal étant écrit.
automatiquement rincer la sortie, vous pouvez définir autoflush/$|
comme décrit par d'autres avant que vous ne sortiez vers le filehandle.
si vous avez déjà sorti le fichier et que vous devez vous assurer qu'il arrive au fichier physique, vous devez utiliser le Io::Handle flush
et sync
méthodes.
Deux solutions:
- Unbuffer le filehandler de sortie avec :
$|
- appeler la méthode autoflush si vous utilisez
IO::Handle
ou un de ses sous-classes.
Voici la réponse, la vraie réponse.
STOP le maintien d'un descripteur de fichier ouvert pour ce fichier pour la durée de vie du processus.
START résumé de votre opération d'ajout de fichier dans un sous-marin qui ouvre le fichier en mode ajout, lui écrit, le ferme.
#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;
}
le processus d'observation du fichier rencontrera un fichier fermé qui sera modifié chaque fois que la fonction est appelée.
Une autre approche serait d'utiliser un canal nommé entre votre script Perl et le programme c++, au lieu du fichier que vous utilisez actuellement.
j'ai eu le même problème avec la seule différence d'écrire le même fichier à plusieurs reprises avec du nouveau contenu. Cette association de "$ / = 1" et d'autoflush a fonctionné pour moi:
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!
bonne chance. H