18

这是我的代码:

<?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 函数的作用。

4

4 回答 4

10

fgets 的长度参数表示最大长度。PHP 文档指出:

当读取到 length - 1 个字节、换行符(包含在返回值中)或 EOF(以先到者为准)时,读取结束。如果没有指定长度,它将继续从流中读取,直到到达行尾。

在您的情况下,第一行包含<!DOCTYPE html>,它解释了 16 给出的结果ftell

于 2015-12-24T03:28:50.707 回答
7

根据fgets()的 PHP 文档,

当读取到 length - 1 个字节、换行符(包含在返回值中)或 EOF(以先到者为准)时,读取结束。

这里的length是你调用时使用的第二个参数fgets(),即1024。因此,当发生以下任何情况时,您的呼叫fgets()将结束阅读:

  1. 它从同一行读取了1023个字节。
  2. 它已到达当前行的末尾。
  3. 它已到达文件末尾。

因此,在您的情况下,当读取第一行时,它在读取16fgets()个字节后到达第一行的末尾,这将是文件指针在旁边调用时的位置。ftell()返回文件指针在文件中的当前位置。ftell()

当您在下一行调用fgets()再次(通过循环迭代while)时,您在文件中的起始位置现在是16(特别是不是 1024),您可以读取最多 (16 + 1024) 1040个字节(最多不超过 2048)。同样,如果您的下一行只有42个字节,这将在58fgets()个字节处结束读取,这将是再次调用时文件指针的位置。ftell()

再次,您fgets()将从58个字节开始,读取最多 (58 + 1024 =) 1082个字节。它将以这种方式继续下去。

的效果fseek()
fseek()用于将文件指针移动到文件中由$offset(第二个参数)设置的特定位置。根据fseek()的 PHP 文档,第三个参数值可以是 -

SEEK_SET-设置位置等于偏移字节。
SEEK_CUR-将位置设置为当前位置加上偏移量。
SEEK_END-将位置设置为文件结尾加上偏移量。

因此,fseek($handle,200000,SEEK_CUR);您将文件指针设置为 200000 + 当前位置。例如,它将在 16 时移动到 200016。

于 2015-12-28T03:59:43.263 回答
3

三个函数可用于设置和确定给定文件的文件指针的位置。

fgets()

从文件指针获取一行。它将假定 1024 作为行长。如果文件中的大多数行都大于 8KB,则脚本指定最大行长度会更节省资源。

返回从句柄指向的文件中读取的最大长度为 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。

于 2015-12-27T14:59:48.713 回答
3

使用 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()具有意外(并且可能不一致)的行为。

于 2015-12-31T08:44:16.503 回答