$archivo->eof() siempre devuelve false cuando el uso de PHP, SplFileObject en 'r' modo
-
13-12-2019 - |
Pregunta
¿Por qué es mi script PHP colgando?
$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 puedo borrar la última línea (iterator_count(...
) y reemplazarlo con este:
$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)
// ...
El $fileObject->eof()
siempre devuelve false, así que conseguir un bucle infinito.
¿Por qué suceden estas cosas?Necesito obtener un número de línea.
Solución
¿Por qué suceden estas cosas?
Usted está experimentando una peculiaridad en la forma en que el SplFileObject
la clase está escrito.Sin llamar next()
y current()
métodos: utilizando el valor predeterminado (0
) banderas—el iterador nunca se mueve hacia adelante.
El iterator_count()
la función de las llamadas no current()
;comprueba valid()
y llamadas next()
sólo.Su medida de bucles sólo llame a uno u otro de current()
y next()
.
Esto debe ser considerado un error (ya sea en PHP, o una falla en la documentación) y el siguiente código debe (y no) funciona como se esperaba.Los invito a el informe de esta mala conducta.
// NOTE: This currently runs in an infinite loop!
$file = new SplFileObject(__FILE__);
var_dump(iterator_count($file));
Soluciones
Un rápido paso lateral para conseguir que las cosas cambien es establecer la READ_AHEAD
la bandera en el objeto.Esto hará que el next()
método para leer la siguiente línea disponible.
$file->setFlags(SplFileObject::READ_AHEAD);
Si, por cualquier razón, usted no desea que el la lectura anticipada comportamiento, a continuación, usted debe llamar a ambos next()
y current()
a ti mismo.
Volver al problema original de dos SplFileObjects
El siguiente ahora debería funcionar como se espera, lo que permite anexar a un archivo de lectura y su número de línea.
<?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));
Otros consejos
EDITADO 01
Si lo que necesitas es el número de líneas dentro del archivo:
<?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
?>
EDITADO 02
Este es el código de arriba, pero sin entrar en bucles infinitos debido a que el puntero de archivo:
<?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();
?>
Salidas
Línea:0 "Foo "
Línea:1 "Barra"
El Total De Líneas:2
RESPUESTA ORIGINAL
De la lógica aplicada fue un poco apagado.He simplificado el código:
<?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>";
}
?>
Salidas:
/tmp/EAdklY.txt
El Archivo Existe:1
Contenido Del Archivo:Foo Bar
Línea:0 Con:"Foo" es el final?no
Línea:1 Con:"Bar" es el final?no
Línea:2 Con:"" es el final?sí
Si bien puede parecer contra intuitivo, con PHP 5.3.9, este:
<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
$f->next();
}
mientras que ser un bucle infinito, y nunca salir.
El siguiente va a salir, cuando el final del archivo:
<?php
$f = new SplFileObject('test.txt', 'r');
while (!$f->eof()) {
$f->current();
}
Así:
$i = 0;
$fileObject2->rewind();
while (!$fileObject2->eof()) {
var_dump($fileObject2->eof());
var_dump($i++);
$fileObject2->next();
}
debe ser reescrita como:
$fileObject2->rewind();
while (!$fileObject2->eof()) {
$fileObject2->current();
}
$i = $fileObject2->key();