【问题标题】:the output of ftell in php functionphp 函数中 ftell 的输出
【发布时间】:2015-12-24 02:16:12
【问题描述】:

这是我的代码:

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


    【解决方案1】:

    fgets的length参数表示最大长度。 PHP documentation 声明:

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

    在你的例子中,第一行包含&lt;!DOCTYPE html&gt;,它解释了ftell给出的16的结果。

    【讨论】:

      【解决方案2】:

      根据fgets() 的 PHP 文档,

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

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

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

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

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

      你将再次从 58 个字节开始下一个fgets(),读取最多 (58 + 1024 =) 1082 个字节。它将继续这样下去。

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

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

      因此,fseek($handle,200000,SEEK_CUR); 将文件指针设置为 200000 + 当前位置。比如16年的时候会移动到200016年。

      【讨论】:

        【解决方案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。 offset 可以是正数、负数或零,但不是所有的 origin 和 offset 组合都可以实现。

        fseek 成功返回 0,错误返回 -1。

        【讨论】:

          【解决方案4】:

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

          【讨论】:

          猜你喜欢
          • 2020-09-19
          • 1970-01-01
          • 1970-01-01
          • 2011-11-03
          • 2011-10-04
          • 1970-01-01
          • 1970-01-01
          • 2011-09-28
          • 1970-01-01
          相关资源
          最近更新 更多