$file->eof() всегда возвращает false при использовании SplFileObject PHP в режиме «r»

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

  •  13-12-2019
  •  | 
  •  

Вопрос

Почему мой PHP-скрипт зависает?

$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

Если я удалю последнюю строку (iterator_count(...) и замените его на это:

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

А $fileObject->eof() всегда возвращает false, поэтому я получаю бесконечный цикл.

Почему эти вещи происходят?Мне нужно получить количество строк.

Это было полезно?

Решение

Почему эти вещи происходят?

Вы ощущаете особенность в том, как SplFileObject класс написан.Без звонка next() и current() методы — используя стандартные (0) flags — итератор никогда не движется вперед.

А iterator_count() функция никогда не вызывает current();он проверяет valid() и звонки next() только.Ваши индивидуальные циклы вызывают только один или другой из current() и next().

Это следует считать ошибкой (будь то в самом PHP или сбоем в документации) и следующий код должен (и не работает) должным образом.Я приглашаю вас сообщить об этом неправомерном поведении.

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

Обходные пути

Одним из быстрых шагов, позволяющих сдвинуть дело с мертвой точки, является установка READ_AHEAD флаг на объекте.Это приведет к next() метод для чтения следующей доступной строки.

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

Если по какой-либо причине вы не хотите читайте дальше поведение, то вы должны вызвать оба next() и current() сам.

Вернемся к исходной проблеме двух SplFileObjects.

Следующее теперь должно работать так, как вы ожидали, позволяя добавлять в файл и читать количество его строк.

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

Другие советы

отредактировано 01

Если то, что вам нужно, это количество строк внутри файла:

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

?>
.



отредактировано 02

Это ваш код выше, но не входя в бесконечные петли из-за указателя файла:

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

?>
.

<Сильные> Выходы

Линия: 0 "foo"

Линия: 1 "бар"

Общие линии: 2



Оригинальный ответ

Наношение логики было немного выключено.Я упростил код:

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

?>
.

<Сильные> Выходы:

/tmp/eadkly.txt

Файл существует: 1

Содержание файла: foo bar

Линия: 0 с: "Foo" - конец?нет

Линия: 1 С: «Бар» - это конец?нет

Линия: 2 с: «» - конец?Да

Хотя может показаться счетчиком интуитивности, с PHP 5.3.9, это:

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

во время бесконечной петли и никогда не выходите.

Ниже придет ниже, когда достигнут конец файла:

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

Так:

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

должен быть переписан как:

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

$i = $fileObject2->key();
.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top