$ File-> EOF () Restituzione sempre false quando si utilizza PHP's SPLFileObject in modalità 'R'

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

  •  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.

È stato utile?

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();
.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top