Вот мой код:
<?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
Content-Length может не совпадать с моим — 518264, он будет динамически изменяться при выполнении кода, это не имеет значения для обсуждения.
Почему результат не следующий?
518264
1024
201024
202048
402048
403072
пожалуйста, объясните действие файлового указателя на функции fgets, ftell и fseek.
Согласно документации PHP для fgets (),
Чтение заканчивается, когда прочитана длина — 1 байт, или новая строка (которая включена в возвращаемое значение), или EOF (что наступит раньше).
Вот длина это второй параметр, который вы использовали при вызове fgets()
, который 1024. Итак, ваш призыв к fgets()
закончит чтение, когда произойдет любое из следующего:
Итак, в вашем случае, когда fgets()
читает первую строку, она достигла конца первой строки после прочтения 16 байт, и это будет позиция указателя файла при вызове ftell()
рядом с ним. ftell () возвращает текущую позицию указателя файла в файле.
Когда вы находитесь в следующей строке, вызывая fgets()
снова (повторяется while
цикл), ваша начальная позиция в файле сейчас 16 (в частности, не 1024), и вы можете прочитать до (16 + 1024) 1040 байты (не до 2048). Опять же, если ваша следующая строка имеет только 42 байты, это fgets()
закончится чтение в 58 байты, которые будут позицией указателя файла при вызове ftell()
снова.
И снова вы собираетесь начать дальше fgets()
от 58 байты, для чтения до (58 + 1024 =) 1082 байт. Так будет и дальше.
Эффект fseek()
fseek()
используется для перемещения файлового указателя на определенную позицию в файле, установленную $ офсет (2-й параматер). Согласно документации PHP для FSEEK (), значения 3-го параметра могут быть —
SEEK_SET
— Установите позицию, равную байту смещения.
SEEK_CUR
— Установить положение в текущее местоположение плюс смещение.
SEEK_END
— Установить позицию в конец файла плюс смещение.
Итак, по fseek($handle,200000,SEEK_CUR);
Вы устанавливаете указатель файла на 200000 + текущая позиция. Например, он перейдет на 200016, когда это было в 16.
Параметр длины в fgets указывает максимальную длину. PHP документация состояния:
Чтение заканчивается, когда прочитана длина — 1 байт, или новая строка (которая включена в возвращаемое значение), или EOF (что наступит раньше). Если длина не указана, он будет продолжать чтение из потока, пока не достигнет конца строки.
В вашем случае первая строка содержит <!DOCTYPE html>
, который объясняет результат 16, данный ftell
,
Три функции доступны для установки и определения позиции указателя файла для данного файла.
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 в случае ошибки.
Используйте функцию 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()
иметь неожиданное (и, вероятно, противоречивое) поведение.