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