使用 PHP 从 1.3GB 文本文件中提取文本的最佳方法


Best way to extract text from a 1.3GB text file using PHP?

我有一个1.3GB的文本文件,我需要从PHP中提取一些信息。我已经研究了它,并提出了几种不同的方法来做我需要做的事情,但一如既往地在稍微澄清了哪种方法最好,或者是否存在我不知道的另一种更好的方法之后?

我在文本文件中需要的信息只是每行的前 40 个字符,文件中大约有 1700 万行。每行的 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 次插入十次。

下一个方法实际上与上述方法相同,但是在执行foreach以获取数据之前调用file()将所有行存储在数组中?我不确定这种方法,因为数组基本上有超过 1700 万个值。

另一种方法是仅提取文件的一部分,使用未使用的数据重写文件,然后在执行该部分后使用header调用调用调用脚本?

最快速和最有效的方式完成这项工作的最佳方法是什么?或者有没有我想到的更好的方法来解决这个问题?

此外,我计划将此脚本与 wamp 一起使用,但是在测试时在浏览器中运行它会导致超时问题,即使将脚本超时设置为 0。有没有办法在不通过浏览器访问页面的情况下执行脚本运行?

到目前为止

你已经很好了,不要使用"file()"函数,因为它很可能会达到RAM使用限制并终止你的脚本。

我什至不会将东西累积到"insert[]"数组中,因为那也会浪费 RAM。如果可以,请立即插入到数据库中。

顺便说一句,有一个叫做"cut"的好工具,您可以使用它来处理文件。

cut -c1-40 file.txt

您甚至可以将cut的stdout重定向到插入到数据库中的一些PHP脚本。

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

然后.php机械臂可以从 php://stdin 读取行并插入数据库。

"cut"是所有Linux上可用的标准工具,如果您使用Windows,则可以使用MinGW shell获取它,或者作为msystools的一部分(如果您使用git)或使用gnuWin32安装本机Win32应用程序。

当你

的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 );

一个查询。

MySQL还具有从命令行包装此功能的mysqlimport实用程序。

以上

都不是。使用fgets()的问题是它没有按预期工作。当达到最大字符数时,对fgets()的下一次调用将在同一行上继续。您已正确识别使用 file() 的问题。第三种方法是一个有趣的想法,您也可以使用其他解决方案来实现它。

也就是说,您使用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插入这么多行;这将大大减少执行时间。当您只能提交数据时,您不希望在每个插入上提交完整查询。