我有一个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次插入。
下一个方法与上面的方法完全相同,但在执行file()
获取数据之前调用foreach
来存储数组中的所有行?我不确定这种方法,因为数组基本上有超过1700万的值。
另一种方法是仅提取文件的一部分,用未使用的数据重写文件,然后在执行该部分之后使用header
调用来调用脚本?
以最快速有效的方式完成这项工作的最佳方法是什么?或者,有没有更好的方法来解决这个问题?
此外,我计划将此脚本与wamp一起使用,但是在测试时在浏览器中运行它会导致超时问题,即使将脚本时间设置为0.有没有办法可以在不访问页面的情况下执行脚本运行通过浏览器?
答案 0 :(得分:5)
到目前为止你还不错,不要使用“file()”函数,因为它最有可能达到RAM使用限制并终止你的脚本。
我甚至不会将内容累积到“insert []”数组中,因为这样会浪费RAM。如果可以,请立即插入数据库。
顺便说一句,有一个很好的工具叫做“cut”,你可以使用它来处理文件。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 shell获取,或者作为msystools的一部分(如果您使用git)或使用gnuWin32安装本机win32应用程序。
答案 1 :(得分: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 );
一个查询。
MySQL还有mysqlimport
实用程序,可以从命令行包装此功能。
答案 2 :(得分:1)
以上都不是。使用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
插入这么多行;这将大大减少执行时间。当您只能提交数据时,您不希望在每个插入上提交完整查询。