J'ai un descripteur de fichier FILE
en Perl, et je veux parcourir toutes les lignes du fichier. Y a-t-il une différence entre les éléments suivants?
while (<FILE>) {
# do something
}
et
foreach (<FILE>) {
# do something
}
J'ai un descripteur de fichier FILE
en Perl, et je veux parcourir toutes les lignes du fichier. Y a-t-il une différence entre les éléments suivants?
while (<FILE>) {
# do something
}
et
foreach (<FILE>) {
# do something
}
Dans la plupart des cas, vous n'aurez probablement pas remarqué une différence. Toutefois, foreach
lit chaque ligne dans une liste (un tableau pas) avant d'aller ligne par ligne, alors que l' while
lit une ligne à la fois. En tant que foreach
utilisera plus de mémoire et nécessitent un temps de traitement initial, il est généralement recommandé d'utiliser while
pour itérer sur les lignes d'un fichier.
MODIFIER (via Schwern): L' foreach
boucle est équivalent à ceci:
my @lines = <$fh>;
for my $line (@lines) {
...
}
Il est malheureux que Perl n'est pas optimiser ce cas spécial, comme il le fait avec l'opérateur d'intervalle (1..10
).
Par exemple, si je lis le fichier /usr/share/dict/words avec un for
boucle et un while
boucle et avoir le sommeil quand ils ont terminé, je peux utiliser ps
de mémoire pour voir le processus est long. Comme un contrôle, j'ai inclus un programme qui ouvre le fichier, mais ne fait rien avec elle.
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND
schwern 73019 0.0 1.6 625552 33688 s000 S 2:47PM 0:00.24 perl -wle open my $fh, shift; for(<$fh>) { 1 } print "Done"; sleep 999 /usr/share/dict/words
schwern 73018 0.0 0.1 601096 1236 s000 S 2:46PM 0:00.09 perl -wle open my $fh, shift; while(<$fh>) { 1 } print "Done"; sleep 999 /usr/share/dict/words
schwern 73081 0.0 0.1 601096 1168 s000 S 2:55PM 0:00.00 perl -wle open my $fh, shift; print "Done"; sleep 999 /usr/share/dict/words
L' for
programme consomme près de 32 mo de mémoire réelle (l' RSS
de la colonne) pour stocker le contenu de mon 2.4 meg /usr/share/dict/words. L' while
boucle stocke uniquement une ligne à un temps juste 70k pour la ligne de mise en mémoire tampon.
Dans un contexte scalaire (i.e. while
) <FILE>
retours chaque ligne à son tour.
Dans un contexte de liste (c'est à dire foreach
) <FILE>
renvoie une liste constituée de chaque ligne du fichier.
Vous devez utiliser l' while
construire.
Voir perlop - I/O Opérateurs pour plus d'.
Edit: j_random_hacker dit à juste titre que
while (<FILE>) { … }
piétine
$_
alors que foreach n'est pas (foreach localise$_
en premier). C'est sûrement la plus importante différence comportementale!
En plus des réponses précédentes, un autre avantage de l'utilisation de while
est que vous pouvez utiliser la variable $.
. Il s'agit du numéro de ligne actuel du dernier descripteur de fichier consulté (voir perldoc perlvar
).
while ( my $line = <FILE> ) {
if ( $line =~ /some_target/ ) {
print "Found some_target at line $.\n";
}
}
J'ai ajouté un exemple traitant de cela à la prochaine édition de la programmation Perl efficace .
Avec un while
, vous pouvez arrêter le traitement FILE
et toujours obtenir les lignes non traitées:
while( <FILE> ) { # scalar context
last if ...;
}
my $line = <FILE>; # still lines left
Si vous utilisez un foreach
, vous consommez toutes les lignes dans le foreach
même si vous arrêtez de les traiter:
foreach( <FILE> ) { # list context
last if ...;
}
my $line = <FILE>; # no lines left!
Mise à jour: j random hacker le souligne dans un commentaire que Perl cas particulier, la fausseté de test dans une boucle while lors de la lecture à partir d'un descripteur de fichier. J'ai juste vérifié que la lecture d'une valeur fausse de ne pas interrompre la boucle -- au moins sur moderne perls. Désolé pour la direction vous avez tout faux. Après 15 années passées à écrire en Perl, je suis encore un noob. ;)
Tout le monde ci-dessus est droite: utilisation de l' while
boucle parce qu'elle sera plus efficace en terme de mémoire et de vous donner plus de contrôle.
Une chose drôle au sujet qu' while
boucle est bien qu'il se ferme lorsque la lecture est faux. Généralement en fin de fichier, mais que si elle renvoie une chaîne vide ou un 0? Oups! Votre programme juste de sortir trop tôt. Cela peut se produire sur n'importe quel fichier de la poignée si la dernière ligne du fichier ne dispose pas d'un retour à la ligne. Il peut aussi arriver avec le fichier de personnalisation d'objets qui ont une méthode de lecture qui ne permet pas de traiter les retours à la ligne de la même manière régulière Perl objets de fichier.
Voici comment résoudre le problème. Vérifier la présence d'une valeur indéfinie de lire ce qui indique la fin du fichier:
while (defined(my $line = <FILE>)) {
print $line;
}
L' foreach
boucle n'ont pas ce problème par la voie, et c'est exact, même si inefficace.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.