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 命令裏使用的參數。

參考文檔

相關文章
相關標籤/搜索