PHP 读取大文件

前言

在平常业务开发过程当中,咱们可能有遇到一些文件相关操做,好比读取大文件啦,好比读取文件最后几行啦,这些操做在 shell 中都比较容易实现,那么在 PHP 中咱们如何实现呢,下面就让咱们来看一下。php

方法一 使用 file 函数

直接使用 file 函数将整个文件读入一个数组内,还能够经过 file_get_contents 函数以字符串形式获取文件的内容。html

咱们来看一下 PHP 官方给的 file 函数的示例:git

<?php
// 将一个文件读入数组。本例中经过 HTTP 从 URL 中取得 HTML 源文件。

$lines = file('http://www.example.com/');

// 在数组中循环,显示 HTML 的源文件并加上行号。

foreach ($lines as $line_num => $line) {
    echo "Line #<b>{$line_num}</b> : " . htmlspecialchars($line) . "<br />\n";
}

// 另外一个例子将 web 页面读入字符串。参见 file_get_contents()。

$html = implode('', file('http://www.example.com/'));

// 从 PHP 5 开始能够使用可选标记参数
$trimmed = file('somefile.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
?>

复制代码

咱们来看一下这样作有什么问题。file 函数会一次性将文件内容读取到内存中,而 PHP 为了防止一些脚本占用了太多的内存而对每一个线程的最大可用内存进行了限制,该限制在 php.ini 中配置,参数为 memory_limitgithub

memory_limit 参数做用是设置了一个脚本容许分配的最大内存量,以字节(bytes)为单位。这有助于防止写得很差的脚本吃掉服务器上全部可用的内存。若是不须要内存限制,请将此指令设置为 -1。默认值为 128Mweb

平常业务开发中,建议不要将该值设置为 -1,不然一旦有哪一个进程耗尽了内存,影响了正常业务,那后果就很是严重了。shell

fgets 逐行读取文件

考虑到一次性读取整个文件会耗费大量的内存,并且假设程序有部分功能是从文件中读取数据,而后去数据库中查找数据,数据库也不可能一次性查找全部数据,所以咱们能够分批查询,对应到文件中能够是一行一行读取。数据库

下面一个方法是计算分配给程序内存的峰值的函数;数组

<?php

    memory_get_peak_usage();

    function formatBytes($bytes, $precision = 2) {
        $units = array("b", "kb", "mb", "gb", "tb");

        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= (1 << (10 * $pow));

        return round($bytes, $precision) . " " . $units[$pow];
    }

    print formatBytes(memory_get_peak_usage());
?>
复制代码

下面一个函数咱们来逐行读取文件,注意最后须要执行 fclose 函数服务器

<?php


    function readTheFile($fileName) {

        $line = [];
        $handle = fopen($fileName, "r");

        while (!feof($handle)) {
            $line[] = ltrim(fgets($handle));
        }

        fclose($handle);

        return $line;
    }

    readTheFile("name.txt");

    require "memory.php";
?>
复制代码

函数功能markdown

  • memory_get_peak_usage — 返回分配给 PHP 内存的峰值
  • fopen — 打开文件或者 URL
  • feof — 测试文件指针是否到了文件结束的位置
  • fgets — 从文件指针中读取一行
  • fclose — 关闭一个已打开的文件指针

使用生成器 yield

生成器介绍

一个生成器函数看起来像一个普通的函数,不一样的是普通函数返回一个值,而一个生成器能够 yield 生成许多它所须要的值。

当一个生成器被调用的时候,它返回一个能够被遍历的对象。当你遍历这个对象的时候(例如经过一个 foreach 循环),PHP 将会在每次须要值的时候调用生成器函数,并在产生一个值以后保存生成器的状态,这样它就能够在须要产生下一个值的时候恢复调用状态。

一旦再也不须要产生更多的值,生成器函数能够简单退出,而调用生成器的代码还能够继续执行,就像一个数组已经被遍历完了。

yield 关键字

生成器函数的核心是 yield 关键字。它最简单的调用形式看起来像一个 return 申明,不一样之处在于普通 return 会返回值并终止函数的执行,而 yield 会返回一个值给循环调用今生成器的代码而且只是暂停执行生成器函数。

测试代码

<?php


    function yieldCommand($fileName) {

        $line = [];
        $handle = fopen($fileName, "r");

        while (!feof($handle)) {
            yield ltrim(fgets($handle));
        }

        fclose($handle);

    }

    foreach (yieldCommand("name.txt") as $key => $value) {
        echo $value;
    }

    require "memory.php";
?>
复制代码

优势

  • 能够优化 php 的性能

  • 节省大量的内存

  • 适合大量数据计算

使用 shell 命令读取文件最后 n 行

当咱们想获取文件中最后几行数据的时候,咱们知道在 shell 中直接使用 tail 命令很是容易得到,那么咱们能不能在 PHP 中执行 shell 命令呢?答案是能够的。

在 PHP 中,咱们有三个函数能够执行 shell 命令,这三个函数分别为 systemexecpassthru。这三个函数的区别以下:

  • system — 执行外部程序,而且显示输出
  • exec — 执行一个外部程序,不输出
  • passthru — 执行外部程序而且显示原始输出

咱们来测试一下:

<?php

    function tailCommand($fileName) {

        $cmd = "tail -n 10 $fileName";

        $result = system($cmd);

        return $result;

    }

    tailCommand("name.txt");

    require "memory.php";
?>
复制代码

escapeshellarg 函数的功能是把字符串转码为能够在 shell 命令里使用的参数。

参考文档

相关文章
相关标签/搜索