我有一个相当大的csv文件(至少对于网络而言)是我无法控制的。它有大约10万行,并且只会变大。
我正在使用Drupal Module Feeds根据这些数据创建节点,并且他们的解析器以50行为一组批量解析。但是,它们的解析器不能正确处理引号,并且无法解析大约60%的csv文件。 fgetcsv可以工作,但是我不知道它是什么。
在尝试使用fgetcsv读取整个文件时,PHP最终会耗尽内存。因此,我希望能够把事情分解成更小的块。这可能吗?
答案 0 :(得分:2)
fgetcsv()
通过从给定文件指针一次读取一行来工作。如果PHP内存不足,或许您正在尝试一次解析整个文件,将它们全部放入一个巨大的数组中。解决方案是逐行处理它而不将其存储在一个大数组中。
要更直接地回答批处理问题,请从文件中读取 n 行,然后使用ftell()
在文件中找到您结束的位置。记下这一点,然后您可以在fseek()
之前调用fgetcsv()
,以便在将来的某个时间点返回。
答案 1 :(得分:2)
好吧,创建一个解析一堆行的函数:
function parseLines(array $lines) {
foreach ($lines as $line) {
//insert line into new node
}
}
然后,只需批量处理:
$numberOfLinesToBatch = 50;
$f = fopen($file, 'r');
if (!$f) die('implement better error checking');
$buffer = array();
while ($row = fgetcsv($f)) {
$buffer[] = $row;
if (count($buffer) >= $numberOfLinesToBatch) {
parseLines($buffer);
$buffer = array();
}
}
if (!empty($buffer)) {
parseLines(buffer);
}
fclose($f);
它将数据流入,您可以通过调整可变数据来调整它缓冲的行数...
答案 2 :(得分:0)
我怀疑问题在于你在内存中存储了太多信息而不是如何从磁盘上读取CSV文件。 (即:fgetcsv一次只会读取一行,所以如果一行数据导致你的内存耗尽,你就会遇到麻烦。)
因此,您只需使用以下方法:
或者,您可以通过命令行版本的PHP执行CSV处理,并使用具有更大内存限制的自定义php.ini。