вывод ftell в функции php

Вот мой код:

<?php
    $url="http://www.sina.com.cn";
    $handle = @fopen($url, "r");
    $len=get_headers($url,true);
    print_r($len);
    echo $len['Content-Length']."\n";
    if ($handle) {
        while (($buffer = fgets($handle,1024)) !== false) {
            echo ftell($handle)."\n";
            fseek($handle,200000,SEEK_CUR);
            echo ftell($handle)."\n";
        }
        if (!feof($handle)) {
            echo "Error: unexpected fgets() fail\n";
        }
        fclose($handle);
    }
?>

Результат выглядит следующим образом:

    Array
(
    [0] => HTTP/1.1 200 OK
    [Content-Type] => text/html
    [Vary] => Accept-Encoding
    [X-Powered-By] => shci_v1.03
    [Server] => nginx
    [Date] => Thu, 24 Dec 2015 04:03:39 GMT
    [Last-Modified] => Thu, 24 Dec 2015 04:01:28 GMT
    [Expires] => Thu, 24 Dec 2015 04:04:39 GMT
    [Cache-Control] => max-age=60
    [Age] => 32
    [Content-Length] => 518264
    [X-Cache] => HIT from xidan33-99.sina.com.cn
    [Connection] => close
)
518264
16
200016
200058
400058
400065
518264

Длина содержимого может быть не такой, как у меня — 518264, она будет динамически изменяться при выполнении кода, это не имеет значения для обсуждения. Почему результат не следующий?

518264
1024
201024
202048
402048
403072

пожалуйста, объясните действие указателя файла на функции fgets и ftell и fseek.


person showkey    schedule 24.12.2015    source источник


Ответы (4)


Согласно документации PHP для fgets(),

Чтение заканчивается, когда длина - 1 байт была прочитана, или новая строка (которая включена в возвращаемое значение), или EOF (в зависимости от того, что наступит раньше).

Здесь length — это второй параметр, который вы использовали при вызове fgets(), который равен 1024. Таким образом, ваш вызов fgets() завершится чтением, когда произойдет одно из следующих событий:

  1. Он прочитал 1023 байта из той же строки.
  2. Достигнут конец текущей строки.
  3. Достигнут конец файла.

Итак, в вашем случае, когда fgets() читает первую строку, он достигает конца первой строки после чтения 16 байтов, и это будет позиция указателя файла при вызове ftell() рядом с ним. ftell() возвращает текущую позицию указателя файла в файле .

Когда вы находитесь в следующей строке, вызывая fgets()again (повторяется циклом while), ваша начальная позиция в файле теперь 16 (особенно не 1024), и вы можете читать до (16 + 1024) < strong>1040 байт (не до 2048). Опять же, если ваша следующая строка имеет только 42 байт, этот fgets() завершит чтение на 58 байтах, что будет позицией указателя файла при повторном вызове ftell().

И снова вы собираетесь начать следующий fgets() с 58 байт, чтобы прочитать до (58 + 1024 =) 1082 байт. Так будет продолжаться.

Эффект fseek()
fseek() используется для перемещения указателя файла в определенную позицию в файле, заданную параметром $offset (второй параметр). Согласно документации PHP для fseek(), значения третьего параметра могут быть -

SEEK_SET – Установить позицию, равную смещению в байтах.
SEEK_CUR – Установить позицию равной текущей позиции плюс смещение.
SEEK_END – Установить позицию, равной концу -файл плюс смещение.

Итак, к fseek($handle,200000,SEEK_CUR); вы устанавливаете указатель файла на 200000 + текущая позиция. Например, он переместится в 200016, когда был в 16.

person Tᴀʀᴇǫ Mᴀʜᴍᴏᴏᴅ    schedule 28.12.2015

Параметр длины fgets указывает максимальную длину. В документации по PHP говорится:

Чтение заканчивается, когда длина - 1 байт была прочитана, или новая строка (которая включена в возвращаемое значение), или EOF (в зависимости от того, что наступит раньше). Если длина не указана, он будет продолжать чтение из потока, пока не достигнет конца строки.

В вашем случае первая строка содержит <!DOCTYPE html>, что объясняет результат 16, заданный ftell.

person Richard St-Cyr    schedule 24.12.2015

Доступны три функции для установки и определения положения указателя файла для данного файла.

fgets()

Получает строку из указателя файла. это предполагает 1024 в качестве длины строки. Если размер большинства строк в файле превышает 8 КБ, для сценария будет более эффективно указывать максимальную длину строки.

Возвращает строку длиной до 1 байта, прочитанную из файла, на который указывает дескриптор. Если больше нет данных для чтения в указателе файла, то возвращается FALSE.

ftell()

Встроенная функция: pos = ftell (fid)

Возвращает позицию указателя файла как количество символов от начала файла, указанного дескриптором файла fid.

fseek()

Встроенная функция: fseek (fid, offset) Встроенная функция: fseek (fid, offset, origin)

Установите указатель файла на смещение местоположения в файле fid.

Указатель расположен со смещением символов от источника, который может быть одной из предопределенных переменных SEEK_CUR (current position), SEEK_SET (beginning), или SEEK_END (end of file) или строк "cof", "bof" or "eof".. Если источник опущен, предполагается SEEK_SET. смещение может быть положительным, отрицательным или нулевым, но не все комбинации исходной точки и смещения могут быть реализованы.

fseek возвращает 0 в случае успеха и -1 в случае ошибки.

person Bhavin Solanki    schedule 27.12.2015

Используйте функцию PHP stream_get_meta_data(), чтобы узнать, открыто доступно для поиска:

$url="http://www.sina.com.cn";
$handle = @fopen($url, "r");

$meta_data = stream_get_meta_data($handle);
var_dump($meta_data['seekable']);

// It prints `bool(false)`

Поток не доступен для поиска. Это означает, что функции fseek(), ftell() и rewind() имеют неожиданное (и, возможно, непоследовательное) поведение.

person axiac    schedule 31.12.2015
comment
В дополнение к этому вы должны проверить возвращаемое значение fseek(), оно должно быть -1 в соответствии с документами ( ar2.php.net/manual/en/function.fseek.php ) - person Joaquín O; 02.01.2016