5

PHPでいくつかの情報を抽出する必要がある1.3GBのテキストファイルがあります。私はそれを研究し、私がする必要があることを行うためのいくつかのさまざまな方法を考え出しましたが、いつものように、どの方法が最善であるか、または私が知らない別のより良い方法が存在するかどうかについて少し明確にした後ですか?

テキストファイルに必要な情報は、各行の最初の40文字だけで、ファイルには約1,700万行あります。各行の40文字がデータベースに挿入されます。

私が持っている方法は以下の通りです。

// REMOVE TIME LIMIT
set_time_limit(0);
// REMOVE MEMORY LIMIT
ini_set('memory_limit', '-1');
// OPEN FILE
$handle = @fopen('C:\Users\Carl\Downloads\test.txt', 'r');
if($handle) {
    while(($buffer = fgets($handle)) !== false) {
        $insert[] = substr($buffer, 0, 40);
    }
    if(!feof($handle)) {
        // END OF FILE
    }
    fclose($handle);
}

上記は一度に各行を読み取り、データを取得します。すべてのデータベース挿入を並べ替えて、トランザクションで一度に50回の挿入を実行します。

次のメソッドは実際には上記と同じですが、データを取得file()する前にすべての行を配列に格納するために呼び出しforeachますか?配列には基本的に1700万を超える値があるため、この方法についてはよくわかりません。

別の方法は、ファイルの一部のみを抽出し、未使用のデータでファイルを書き換え、その部分が実行された後、呼び出しを使用してスクリプトをheader呼び出すことです。

これを最も迅速かつ効率的な方法で行うための最良の方法は何でしょうか?それとも、私が考えていたこれにアプローチするためのより良い方法はありますか?

また、このスクリプトをwampで使用する予定ですが、テスト中にブラウザーで実行すると、スクリプトのタイムアウトを0に設定しても、タイムアウトの問題が発生します。ブラウザーからページにアクセスせずにスクリプトを実行して実行する方法はありますか? ?

4

3 に答える 3

5

これまでのところ問題はありません。RAM使用量の制限に達してスクリプトを終了する可能性が高いため、「file()」関数は使用しないでください。

RAMも浪費するので、「insert[]」配列にデータを蓄積することすらしません。可能であれば、すぐにデータベースに挿入してください。

ところで、ファイルの処理に使用できる「カット」と呼ばれる優れたツールがあります。

cut -c1-40 file.txt

cutのstdoutを、データベースに挿入するPHPスクリプトにリダイレクトすることもできます。

cut -c1-40 file.txt | php -f inserter.php

次に、inserter.phpはphp:// stdinから行を読み取り、DBに挿入できます。

「cut」はすべてのLinuxで利用できる標準ツールです。Windowsを使用している場合は、MinGWシェルで取得できます。または、msystoolsの一部として(gitを使用している場合)、gnuWin32を使用してネイティブwin32アプリをインストールできます

于 2012-06-06T23:54:44.923 に答える
2

RDBMSに一括インポート機能がほぼ確実に組み込まれているのに、なぜPHPでこれを行うのですか?たとえば、MySQLには次のものがありますLOAD DATA INFILE

LOAD DATA INFILE 'data.txt'
INTO TABLE `some_table`
  FIELDS TERMINATED BY ''
  LINES TERMINATED BY '\n';
  ( @line )
SET `some_column` = LEFT( @line, 40 );

1つのクエリ。

MySQLにはmysqlimport、コマンドラインからこの機能をラップするユーティリティもあります。

于 2012-06-07T00:05:21.103 に答える
1

上記のどれでもない。使用上の問題は、fgets()期待どおりに機能しないことです。最大文字数に達すると、次の呼び出しfgets()は同じ行で続行されます。を使用して問題を正しく特定しましたfile()。3番目の方法は興味深いアイデアであり、他のソリューションでもそれを実現できます。

とは言うものの、使用するという最初のアイデアfgets()はかなり近いものですが、その動作を少し変更する必要があります。期待どおりに機能するカスタマイズバージョンは次のとおりです。

function fgetl($fp, $len) {
    $l = 0;
    $buffer = '';
    while (false !== ($c = fgetc($fp)) && PHP_EOL !== $c) {
        if ($l < $len)
            $buffer .= $c;
        ++$l;
    }
    if (0 === $l && false === $c) {
        return false;
    }
    return $buffer;
}

すぐに挿入操作を実行してください。そうしないと、メモリが無駄になります。prepared statementsこの数の行を挿入するために使用していることを確認してください。これにより、実行時間が大幅に短縮されます。データのみを送信できる場合は、挿入ごとに完全なクエリを送信する必要はありません。

于 2012-06-07T00:11:29.927 に答える