«Unread_bytes» потока говорит 0, но не 0

0

Я работаю над небольшим количеством кода, который читает файл и возвращает его в сегменты "линии" заданного количества байтов. Теперь я столкнулся с проблемой, когда на отметке 8192 байта в файле размером более 8192 байта возникает странное поведение, когда stream_get_meta_data() возвращает unread_bytes из 0 несмотря на то, что читается больше, а последующее чтение получает его просто но форматирование взломано.

Я сократил свой код до минимального примера:

if(count($argv) > 1 && is_file($argv[count($argv)-1])) {
    if( ! $fh = fopen($argv[count($argv)-1], 'r') ) {
        die('Could not open file.');
    }
} else if( $fh = STDIN ) {
} else { die('No file and could not open stdin'); }

$linesize = 24; // typical line size
$bufsize = 4096; // default buffer size
$buffer = '';
$offset = 0;
$output = '';
while($buffer .= fread($fh, $bufsize)) {
    $s = strlen($buffer);
    for( $i=0; $i<$s; $i+=$linesize ) {
        // if we're not yet at the end of the file
        // if there not enough left in the buffer for a full line
        // reset the buffer to the remainder of the buffer and break to outer loop
        printf("off:%d s:%d i:%d b:%d\n", $offset, $s, $i, ( $s-$i < $linesize ));
        if( $s-$i < $linesize ) {
            $meta = stream_get_meta_data($fh);
            printf("break? unread_bytes:%d eof:%d\n", $meta['unread_bytes'], $meta['eof']);
            if( $meta['unread_bytes'] !== 0 ) {
                $buffer = substr($buffer, $i);
                echo "broke\n";
                continue 2;
            }
        }
//      echo substr($buffer, $i, $linesize)."\n";
        $offset += $linesize;
    }
    $buffer = '';
}

fclose($fh);

Вывод:

off:0 s:4096 i:0 b:0
off:24 s:4096 i:24 b:0
off:48 s:4096 i:48 b:0
[snip]
off:4032 s:4096 i:4032 b:0
off:4056 s:4096 i:4056 b:0
off:4080 s:4096 i:4080 b:1
break? unread_bytes:4096 eof:0
broke
off:4080 s:4112 i:0 b:0
off:4104 s:4112 i:24 b:0
off:4128 s:4112 i:48 b:0
[snip]
off:8136 s:4112 i:4056 b:0
off:8160 s:4112 i:4080 b:0
off:8184 s:4112 i:4104 b:1
break? unread_bytes:0 eof:0
off:8208 s:303 i:0 b:0
off:8232 s:303 i:24 b:0
off:8256 s:303 i:48 b:0
off:8280 s:303 i:72 b:0
off:8304 s:303 i:96 b:0
off:8328 s:303 i:120 b:0
off:8352 s:303 i:144 b:0
off:8376 s:303 i:168 b:0
off:8400 s:303 i:192 b:0
off:8424 s:303 i:216 b:0
off:8448 s:303 i:240 b:0
off:8472 s:303 i:264 b:0
off:8496 s:303 i:288 b:1
break? unread_bytes:0 eof:0
[actual end of file]

Вы можете видеть, что при среднем перерыве метаданные потока указывают, что осталось 0 байтов, но после этого он возвращается к внешнему циклу и читает снова. Какая сделка?

Кроме того, я не использую feof($fh) или $meta['eof'] потому что он не кажется установленным при чтении из stdin, который вы также можете увидеть в примере.

Теги:

1 ответ

1
Лучший ответ

В документации указано: unread_bytes:

Примечание. Вы не должны использовать это значение в скрипте.

Тем не менее, похоже, вы делаете это намного сложнее, чем строго необходимо:

while (!feof($fh)) {
    $line = fread($fh, $linesize);
    if (strlen($line) < $linesize) {
        break;
    }
    // do what you want
}
  • 0
    Я думаю, что перепутал воспоминания о нескольких разных проектах / языках, когда писал этот сценарий. Как правило, чтение файла по 24 байта за раз является ужасной идеей, но потоковая оболочка PHP автоматически читает в 8K-буфере, что снимает эту проблему. Как только этот внешний цикл исчезнет, feof() также снова начнет работать нормально.
  • 0
    @Sammitch Да, ура для буферизованных потоков \ o /

Ещё вопросы

Сообщество Overcoder
Наверх
Меню