PHP函数中ftell的输出

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

内容长度可能与我的不同--518264,执行代码时它会动态变化,但对于讨论来说并不重要。 为什么结果不是以下内容?

518264
1024
201024
202048
402048
403072
请解释fgets函数、ftell函数和fseek函数对文件指针的作用。
4个回答

10

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

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

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


7
根据PHP文档中fgets()的说明:读取操作在以下情况下结束,先到哪个条件就结束:已经读取了长度减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设置。根据PHP文档中fseek()的说明,第三个参数的值可以是: SEEK_SET - 将位置设置为偏移量字节。
SEEK_CUR - 将位置设置为当前位置加上偏移量。
SEEK_END - 将位置设置为文件末尾加上偏移量。

所以,通过 fseek($handle,200000,SEEK_CUR); 你可以将文件指针设置为当前位置加上 200000。例如,当它在 16 时,它将移动到 200016。


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() 的行为是意外的(而且可能不一致)。

1
此外,您应该检查fseek()的返回值,根据文档(http://ar2.php.net/manual/en/function.fseek.php),它应该是`-1`。 - Joaquín O

3

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

fgets()

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

返回一个字符串,其中包含由句柄指向的文件读取的最多长度-1 字节。如果在文件指针中没有更多数据可读,则返回 FALSE

ftell()

内置函数: pos = ftell (fid)

返回文件指针的位置,作为文件描述符 fid 指定的文件开头处的字符数。

fseek()

内置函数: fseek (fid, offset) 内置函数: fseek (fid, offset, origin)

将文件指针设置为文件 fid 中的偏移量位置。

指针位于距离原点 offset 个字符处,原点可能是预定义变量之一 SEEK_CUR(当前位置),SEEK_SET(开头)SEEK_END(文件结尾) 或字符串 "cof"、"bof" 或 "eof"。如果省略原点,则假定 SEEK_SET。offset 可以是正数、负数或零,但不能实现所有原点和偏移量的组合。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接