按行读取文件内容(实现分页加载文件内容)

  对于小文件可以使用file()函数把整个文件的内容都读入内存:

<?php
declare(strict_types=1);
ini_set('display_errors', 'On');
error_reporting(-1);

$filename = __DIR__ . '/date.txt';

// 读取文件内容
// --------------------------------------------------
// 说明(1):文件内容以数组形式返回,读取失败则返回false。
// 说明(2):一个数组元素存放一行文件内容。
// 说明(3):每行文件内容结尾会附加换行符。
// 说明(4):末尾空行不算一行(不输出行内容,也不算入总行数)。
$contents = file($filename);

if (is_array($contents)) {
    $count = count($contents);
    echo "===== 共{$count}行 =====" . PHP_EOL; // ===== 共366行 =====

    // 输出文件每一行内容
    foreach ($contents as $line => $text) {
        $num = (string)($line + 1); // 行号
        $num = str_pad($num, 3, '0', STR_PAD_LEFT); // 行号不足3位时左侧补零保持美观

        $text = trim($text); // 由于每行文件内容结尾会附加换行符,这里去掉换行符

        echo "第{$num}行:$text" . PHP_EOL;
    }
    // 第001行:2000-01-01
    // 第002行:2000-01-02
    // 第003行:2000-01-03
    // 第004行:2000-01-04
    // 第005行:2000-01-05
    // ……(此处省略内容若干)……
    // 第362行:2000-12-27
    // 第363行:2000-12-28
    // 第364行:2000-12-29
    // 第365行:2000-12-30
    // 第366行:2000-12-31
}



  对于大文件把整个文件的内容都读入内存显然是不现实的,只能分段读取:

<?php
declare(strict_types=1);
ini_set('display_errors', 'On');
error_reporting(-1);

$filename = __DIR__ . '/date.txt';

$handle = fopen($filename, 'rb'); // 打开文件

is_resource($handle) || exit('打开文件失败');

//========== 读取单一行内容(基本原理) ==========//
rewind($handle); // 将文件指针移回文件开头
$current = 1; // 文件指针当前位置,即哪一行
$line = 128; // 指定行号
while ($current < $line) {
    fgets($handle, 4096); // 使用fgets()将文件指针移到下一行,由于是无关行,所以不需要使用变量接收返回值
    $current++; // 由于上面fgets()将文件指针移到了下一行,变量$current也要自增1
}
$contents = fgets($handle, 4096); // 读取内容
($contents === false) && ($contents = ''); // 判断是否到文件尾(EOF)或出错
$contents = rtrim($contents, PHP_EOL); // 删除结尾的换行符
echo "单行·第{$line}行:$contents" . PHP_EOL; // 单行·第128行:2000-05-07

//========== 读取范围行内容(分页效果) ==========//
rewind($handle); // 将文件指针移回文件开头
$current = 1; // 文件指针当前位置,即哪一行
$size = 10; // 每页10行
$page = 13; // 读取第13页的内容,即121~130行的内容
$start = ($page - 1) * $size + 1; // 算出起始行号,即121
$end = $start + $size - 1; // 算出结束行号,即130
while ($current < $start) {
    fgets($handle, 4096); // 使用fgets()将文件指针移到下一行,由于是无关行,所以不需要使用变量接收返回值
    $current++; // 由于上面fgets()将文件指针移到了下一行,变量$current也要自增1
}
while ($current <= $end) {
    $contents = fgets($handle, 4096); // 读取内容
    ($contents === false) && ($contents = ''); // 判断是否到文件尾(EOF)或出错
    $contents = rtrim($contents, PHP_EOL); // 删除结尾的换行符
    echo "多行·第{$current}行:$contents" . PHP_EOL;
    $current++; // 由于上面fgets()将文件指针移到了下一行,变量$current也要自增1
}
// 多行·第121行:2000-04-30
// 多行·第122行:2000-05-01
// 多行·第123行:2000-05-02
// 多行·第124行:2000-05-03
// 多行·第125行:2000-05-04
// 多行·第126行:2000-05-05
// 多行·第127行:2000-05-06
// 多行·第128行:2000-05-07
// 多行·第129行:2000-05-08
// 多行·第130行:2000-05-09

fclose($handle); // 关闭文件

//========== 总结 ==========//
// 1、PHP并没有能够直接将文件指针移到指定行的函数,fseek()也只是按字节数移动指针,无法实现按行移动。
// 2、fgets()读取了文件指针所在行的内容后会自动将指针移到下一行,这也是唯一能让文件指针逐行移动的函数。

Copyright © 2024 码农人生. All Rights Reserved