web-dev-qa-db-ja.com

ファイルの内容を読み取るための最速の方法

OK、サーバー上のファイルパスを使用して、PHP経由でファイルのすべてのコンテンツを読み取るための可能な限り高速な方法を探しています。また、これらのファイルは巨大になる可能性があります。そのため、できるだけ速く読み取り専用にすることが非常に重要です。

コンテンツ全体を読むよりも、行ごとに速く読んでいますか?ただし、この内容を読んだことを覚えています。内容全体を読むと、巨大なファイルに対してエラーが発生する可能性があります。これは本当ですか?

28
SoLoGHoST

ファイルの全内容をPHP変数にロードする場合、最も簡単な(そしておそらく最速)の方法は- file_get_contents

ただし、大きなファイルで作業している場合、ファイル全体をメモリにロードすることはあまり良い考えではないかもしれません。おそらく、 memory_limit エラー、PHPは、スクリプトが以上(通常)数メガバイトのメモリ。


したがって、たとえ最速の解決策ではない場合でも、ファイルを1行ずつfopen + fgets + fclose、およびファイル全体をメモリにロードせずにそれらの行をオンザフライで操作すると、必要...

35
Pascal MARTIN

file_get_contents()は、PHPでファイルを読み取るための最も最適化された方法です。ただし、メモリでファイルを読み取るため、常に使用可能なメモリ量に制限されます

適切な権限を持っている場合はini_set('memory_limit', -1)を発行できますが、システムで使用可能なメモリ量によって制限されます。これはすべてのプログラミング言語に共通です。

唯一の解決策は、ファイルをチャンクで読み取ることです。そのため、file_get_contents()を4番目と5番目の引数($offsetおよび$maxlen-bytes):

string file_get_contents(string $filename[, bool $use_include_path = false[, resource $context[, int $offset = -1[, int $maxlen = -1]]]])

この手法を使用して大きなダウンロードファイルを提供する例を次に示します。

public function Download($path, $speed = null)
{
    if (is_file($path) === true)
    {
        set_time_limit(0);

        while (ob_get_level() > 0)
        {
            ob_end_clean();
        }

        $size = sprintf('%u', filesize($path));
        $speed = (is_int($speed) === true) ? $size : intval($speed) * 1024;

        header('Expires: 0');
        header('Pragma: public');
        header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
        header('Content-Type: application/octet-stream');
        header('Content-Length: ' . $size);
        header('Content-Disposition: attachment; filename="' . basename($path) . '"');
        header('Content-Transfer-Encoding: binary');

        for ($i = 0; $i <= $size; $i = $i + $speed)
        {
            ph()->HTTP->Flush(file_get_contents($path, false, null, $i, $speed));
            ph()->HTTP->Sleep(1);
        }

        exit();
    }

    return false;
}

別のオプションは、最適化されていないfopen()feof()fgets()、およびfclose()関数を使用することです。行全体を一度に取得する場合は特に、これは 大規模なSQLクエリをデータベースにインポートするための別のStackOverflow質問で提供した別の例

function SplitSQL($file, $delimiter = ';')
{
    set_time_limit(0);

    if (is_file($file) === true)
    {
        $file = fopen($file, 'r');

        if (is_resource($file) === true)
        {
            $query = array();

            while (feof($file) === false)
            {
                $query[] = fgets($file);

                if (preg_match('~' . preg_quote($delimiter, '~') . '\s*$~iS', end($query)) === 1)
                {
                    $query = trim(implode('', $query));

                    if (mysql_query($query) === false)
                    {
                        echo '<h3>ERROR: ' . $query . '</h3>' . "\n";
                    }

                    else
                    {
                        echo '<h3>SUCCESS: ' . $query . '</h3>' . "\n";
                    }

                    while (ob_get_level() > 0)
                    {
                        ob_end_flush();
                    }

                    flush();
                }

                if (is_string($query) === true)
                {
                    $query = array();
                }
            }

            return fclose($file);
        }
    }

    return false;
}

どの手法を使用するかは、実際に何をしようとしているかによって異なります(SQLインポート関数とダウンロード関数で確認できます)が、常にチャンクでデータを読み取る必要があります

15
Alix Axel
$file_handle = fopen("myfile", "r");
while (!feof($file_handle)) {
   $line = fgets($file_handle);
   echo $line;
}
fclose($file_handle);
  1. ファイルを開き、ファイル自体への参照として$file_handleに保存します。
  2. すでにファイルの最後にいるかどうかを確認してください。
  3. 最後までファイルを読み続け、読みながら各行を印刷します。
  4. ファイルを閉じます。
8
Sanjay Khatri

file_get_contents

例:

$homepage = file_get_contents('http://www.example.com/');
echo $homepage;
5
Sarfraz

Fpassthruまたはreadfileを使用します。どちらもファイルサイズが大きくなるにつれて、一定のメモリを使用します。

http://raditha.com/wiki/Readfile_vs_include

2
ACME Squares
foreach (new SplFileObject($filepath) as $lineNumber => $lineContent) {

    echo $lineNumber."==>".$lineContent;  
    //process your operations here
}
1
ashraf mohammed

一度にファイル全体を読み取る方が高速です。

ただし、大きなファイルはすべてのメモリを使い果たし、問題を引き起こす可能性があります。それからあなたの最も安全な賭けは行ごとに読むことです。

0
zaf

メモリとファイルサイズが気にならない場合は、

$lines = file($path);

この場合、$ linesはファイルの配列です。

0
ppostma1