$ File-> EOF () Restituzione sempre false quando si utilizza PHP's SPLFileObject in modalità 'R'
-
13-12-2019 - |
Domanda
Perché il mio script PHP è appeso?
$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
.
Se elimino l'ultima riga (iterator_count(...
) e lo sostituisci con questo:
$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)
// ...
.
Il $fileObject->eof()
restituisce sempre falso in modo da ottenere un ciclo infinito.
Perché queste cose stanno accadendo?Ho bisogno di ottenere un conteggio della linea.
Soluzione
Perché queste cose stanno accadendo?
Stai vivendo una peculiarità nel modo in cui è scritta la classe SplFileObject
. Senza chiamare next()
e Metodi current()
: utilizzando i flag predefiniti (0
): l'iteratore non si muove mai in avanti.
La funzione iterator_count()
non chiama mai current()
; Controlla valid()
e chiama solo next()
. I tuoi anelli su misura chiamano solo uno o l'altro di current()
e next()
.
Questo dovrebbe essere considerato un bug (se in PHP stesso o un fallimento nella documentazione) e il seguente codice dovrebbe (e non) funziona come previsto. Ti invito a Segnala questo comportamento scorretto .
// NOTE: This currently runs in an infinite loop!
$file = new SplFileObject(__FILE__);
var_dump(iterator_count($file));
.
Workarounds
un rapido sidestep per ottenere cose che si muove è impostare il flag READ_AHEAD
sull'oggetto. Ciò causerà il metodo next()
di leggere la prossima riga disponibile.
$file->setFlags(SplFileObject::READ_AHEAD);
.
Se, per qualsiasi motivo, non si desidera il comportamento Leggi AFFERTE , è necessario chiamare sia next()
che current()
da solo.
Torna al problema originale di due SPLFileObjects
Quanto segue dovrebbe ora funzionare come previsto, consentendo l'aggiunta di un file e la lettura del conteggio della linea.
<?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));
. Altri suggerimenti
modificato 01
Se ciò di cui hai bisogno è il numero di righe all'interno del file:
<?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
?>
.
.
modificato 02
Questo è il tuo codice sopra, ma senza entrare in loop infiniti dovuto al puntatore del file:
<?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();
?>
.
Uscite
.Linea: 0 "Foo"
Linea: 1 "bar"
Linee totali: 2
.
Risposta originale
La logica applicata era un po 'spento.Ho semplificato il codice:
<?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>";
}
?>
.
Uscite:
./tmp/eadkly.txt
File esiste: 1
Contenuto del file: foo bar
Linea: 0 con: "Foo" è la fine?no
Linea: 1 con: "Bar" è la fine?no
Linea: 2 con: "" è la fine?Sì
Mentre può sembrare intuitivo, con PHP 5.3.9, questo:
<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
$f->next();
}
.
pur essere un ciclo infinito e non uscire mai.
Quanto segue uscirà, quando viene raggiunta la fine del file:
<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
$f->current();
}
.
Allora:
$i = 0;
$fileObject2->rewind();
while (!$fileObject2->eof()) {
var_dump($fileObject2->eof());
var_dump($i++);
$fileObject2->next();
}
.
dovrebbe essere riscritto come:
$fileObject2->rewind();
while (!$fileObject2->eof()) {
$fileObject2->current();
}
$i = $fileObject2->key();
.