$fichier->eof() retourne toujours false lors de l'utilisation de PHP SplFileObject en " r " à la mode

StackOverflow https://stackoverflow.com//questions/11706174

  •  13-12-2019
  •  | 
  •  

Question

Pourquoi mon script PHP en suspens?

$path = tempnam(sys_get_temp_dir(), '').'.txt';
$fileInfo = new \SplFileInfo($path);
$fileObject = $fileInfo->openFile('a');
$fileObject->fwrite("test line\n");
$fileObject2 = $fileInfo->openFile('r');
var_dump(file_exists($path));          // bool(true)
var_dump(file_get_contents($path));    // string(10) "test line
                                       // "
var_dump(iterator_count($fileObject2)); // Hangs on this

Si je supprime la dernière ligne (iterator_count(...) et de le remplacer par ceci:

$i = 0;
$fileObject2->rewind();
while (!$fileObject2->eof()) {
    var_dump($fileObject2->eof());
    var_dump($i++);
    $fileObject2->next();
}

// Output:
// bool(false)
// int(0)
// bool(false)
// int(1)
// bool(false)
// int(2)
// bool(false)
// int(3)
// bool(false)
// int(4)
// ...

L' $fileObject->eof() renvoie toujours false si je reçois une boucle infinie.

Pourquoi ces choses se produire?J'ai besoin d'obtenir un nombre de lignes.

Était-ce utile?

La solution

Pourquoi ces choses se produire?

Vous rencontrez une particularité dans la manière que l' SplFileObject la classe est écrit.Sans appel next() et current() méthodes—l'utilisation de la valeur par défaut (0) indicateurs—l'itérateur ne jamais se déplace vers l'avant.

L' iterator_count() la fonction n'appelle jamais current();il vérifie valid() et les appels next() seulement.Votre sur mesure boucles d'appeler uniquement une ou l'autre de current() et next().

Cela devrait être considéré comme un bug (que ce soit en PHP lui-même, ou une défaillance dans la documentation) et le code suivant devrait (et) ne s'applique pas fonctionner comme prévu.Je vous invite à le rapport présente les débordements.

// NOTE: This currently runs in an infinite loop!
$file = new SplFileObject(__FILE__);
var_dump(iterator_count($file));

Solutions de contournement

Un rapide pas de côté pour faire bouger les choses est de mettre la READ_AHEAD drapeau sur l'objet.Ce sera la cause de la next() méthode pour lire la prochaine ligne disponible.

$file->setFlags(SplFileObject::READ_AHEAD);

Si, pour une raison quelconque, vous ne voulez pas le lire à l'avance comportement, alors vous devez appeler à la fois next() et current() vous-même.

De retour au problème initial de deux SplFileObjects

La suite devrait maintenant fonctionner comme prévu, permettant l'ajout d'un fichier et la lecture de son nombre de lignes.

<?php
$info = new SplFileInfo(__FILE__);
$write = $info->openFile('a');
$write->fwrite("// new line\n");
$read = $info->openFile('r');
$read->setFlags(SplFileObject::READ_AHEAD);
var_dump(iterator_count($read));

Autres conseils

ÉDITÉ 01

Si ce que vous avez besoin est le nombre de lignes dans le fichier:

<?php

$path = tempnam(sys_get_temp_dir(), '').'.txt';

$fileInfo = new SplFileInfo($path);
$fileObject = $fileInfo->openFile('a+');

$fileObject->fwrite("Foo".PHP_EOL);
$fileObject->fwrite("Bar".PHP_EOL);

echo count(file($path));  // outputs 2

?>


ÉDITÉ 02

C'est votre code ci-dessus, mais sans entrer dans une boucle infinie en raison du pointeur de fichier:

<?php

$path = tempnam(sys_get_temp_dir(), '').'.txt';

$fileInfo = new SplFileInfo($path);
$fileObject = $fileInfo->openFile('a+');

$fileObject->fwrite("Foo".PHP_EOL);
$fileObject->fwrite("Bar");

foreach($fileObject as $line_num => $line) {
    echo 'Line: '.$line_num.' "'.$line.'"'."<br/>";
}
echo 'Total Lines:' . $fileObject->key();

?>

Sorties

Ligne:0 "Foo "

Ligne:1 "Bar"

Nombre De Lignes:2



RÉPONSE ORIGINALE À CETTE QUESTION

De la logique appliquée en était un peu éteint.J'ai simplifié le code:

<?php

// set path to tmp with random file name
echo $path = tempnam(sys_get_temp_dir(), '').'.txt';
echo "<br/>";

// new object
$fileInfo = new \SplFileInfo($path);

// open to write
$fileObject = $fileInfo->openFile('a');

// write two lines
$fileObject->fwrite("Foo".PHP_EOL);
$fileObject->fwrite("Bar".PHP_EOL);

// open to read
$fileObject2 = $fileInfo->openFile('r');

// output contents
echo "File Exists: " .file_exists($path);
echo "<br/>";
echo "File Contents: " . file_get_contents($path);
echo "<br/>";

// foreach line get line number and line contents 
foreach($fileObject2 as $line_num => $line) {
  echo 'Line: '.$line_num;
  echo ' With: "'.$line.'" is the end? '.($fileObject2->eof()?'yes':'no')."<br>";
}

?>

Sorties:

/tmp/EAdklY.txt

Le Fichier Existe:1

Le Contenu Du Fichier:Foo Bar

Ligne:0 Avec:"Foo" est la fin?pas de

Ligne:1 Avec:"Bar ", c'est la fin?pas de

Ligne:2 Avec:"" est-ce la fin?oui

Même si cela peut sembler contre-intuitif, avec PHP 5.3.9, ceci:

<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
    $f->next();
}

tout être une boucle infinie, et de ne jamais quitter.

À la suite d'une sortie de, lorsque la fin du fichier est atteinte:

<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
    $f->current();
}

Donc:

$i = 0;
$fileObject2->rewind();
while (!$fileObject2->eof()) {
    var_dump($fileObject2->eof());
    var_dump($i++);
    $fileObject2->next();
}

devrait être réécrit comme suit:

$fileObject2->rewind();
while (!$fileObject2->eof()) {
    $fileObject2->current();
}

$i = $fileObject2->key();
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top