$file->eof() gibt immer false zurück, wenn PHPs SplFileObject im „r“-Modus verwendet wird

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

  •  13-12-2019
  •  | 
  •  

Frage

Warum hängt mein PHP-Skript?

$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

Wenn ich die letzte Zeile lösche (iterator_count(...) und ersetzen Sie es durch Folgendes:

$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)
// ...

Der $fileObject->eof() Gibt immer false zurück, sodass ich eine Endlosschleife erhalte.

Warum passieren diese Dinge?Ich muss eine Zeilenanzahl ermitteln.

War es hilfreich?

Lösung

Warum passieren diese Dinge?

Sie erleben eine Besonderheit in der Art und Weise, wie die SplFileObject Klasse ist geschrieben.Ohne anzurufen next() Und current() Methoden – unter Verwendung der Standardeinstellung (0) Flags – der Iterator bewegt sich nie vorwärts.

Der iterator_count() Funktion ruft nie auf current();es prüft valid() und Anrufe next() nur.Ihre maßgeschneiderten Schleifen rufen nur das eine oder andere auf current() Und next().

Dies sollte als Fehler (sei es in PHP selbst oder als Fehler in der Dokumentation) und im folgenden Code betrachtet werden sollen (und funktioniert nicht) wie erwartet.ich lade dich ein zu Melden Sie dieses Fehlverhalten.

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

Problemumgehungen

Ein schneller Nebenschritt, um die Dinge in Gang zu bringen, besteht darin, das festzulegen READ_AHEAD Flagge auf dem Objekt.Dies wird dazu führen, dass next() Methode zum Lesen der nächsten verfügbaren Zeile.

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

Wenn Sie das aus irgendeinem Grund nicht möchten lesen Sie weiter Verhalten, dann müssen Sie beide anrufen next() Und current() selbst.

Zurück zum ursprünglichen Problem zweier SplFileObjects

Das Folgende sollte nun wie erwartet funktionieren und das Anhängen an eine Datei und das Lesen der Zeilenanzahl ermöglichen.

<?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));

Andere Tipps

BEARBEITET 01

Wenn Sie die Anzahl der Zeilen in der Datei benötigen:

<?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

?>


BEARBEITET 02

Dies ist Ihr Code oben, jedoch ohne in Endlosschleifen aufgrund des Dateizeigers einzusteigen:

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

?>

Ausgänge

Linie:0 „Foo“

Linie:1 „Bar“

Gesamtzeilen:2



URSPRÜNGLICHE ANTWORT

Die angewandte Logik war etwas daneben.Ich habe den Code vereinfacht:

<?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>";
}

?>

Ausgänge:

/tmp/EAdklY.txt

Datei existiert:1

Dateiinhalt:Foo Bar

Linie:0 Mit:„Foo“ ist das Ende?NEIN

Linie:1 Mit:„Bar“ ist das Ende?NEIN

Linie:2 Mit:"" das ist das Ende?Ja

Auch wenn es kontraintuitiv erscheinen mag, gilt bei PHP 5.3.9 Folgendes:

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

while sei eine Endlosschleife und werde niemals beendet.

Folgendes wird beendet, wenn das Ende der Datei erreicht ist:

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

Also:

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

sollte umgeschrieben werden als:

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

$i = $fileObject2->key();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top