我有一个26MB的CSV文件。不大也不小。我正在使用file_get_contents读取整个文件。
$lines = explode(NEWLINE, file_get_contents($fname));
第一行是标题,所以我使用explode(',',$ line)将标题行转换为标题数组($ hdrs)。从那里我摆脱了大约1/3的标题 - 它们是从我保留的列计算的值。
$hdrs = explode(',', $lines[0]);
foreach ($hdrs AS $key=>$hdr) {
if (strpos($hdr, $srchStr) !== FALSE) { unset($hdrs[$key]; }
}
$hdrs = array_flip($hdrs);
然后我循环遍历每一行并像这样处理该行:
foreach ($lines AS $key=>$line) {
$data = explode(',', $line);
unset($lines[$key], $key, $line);
// This maps the array from keys 0, 1, 2, ... to the header fields
// It also eliminates any data fields not in the reduced $hdrs var
$data = remap_data($data, $hdrs);
// There are several line type and each line type has a subset of
// the now reduced data that is important
$type = determine_linetype($data);
// Depending on the line type I eliminate even more data
$data = further_reduce_data($data, $type);
// Here I ave the data to an array; this is AdWords account data so I have ad
// Campaigns at the top then Ad Groups then Keywords, ...
// I use a switch to determine where the data should go into the array
switch ($type) {
case Keyword:
$reducedData[$campaign][$adgroup]['KWs'][$kw] = $data;
break;
...
}
}
此循环按预期工作,并按照我想要的方式组织数据。它也消除了不必要的数据。
我正在使用的测试文件中有72000行。大约一半的脚本耗尽了内存。我可以将脚本的可用内存增加三倍,我有RAM。但是,我错误地认为,我使用它们时未设置的行以及从每行中删除一半以上的数据最终会导致有组织的数组使用的内存少于完全加载的CSV文件。此外,使用的内存在此行unset($lines[$key], $key, $line);
之后跳过大约4.5 MB,这对我没有意义,但我已经多次测试过了。
当我减少$ data数组中的数据时,我通过创建一个var $输出并保存我想要保存到$ output的所有$ data然后从函数返回$ output来覆盖原始的$ data - 即$data = reduce_data($data);
。
我也尝试将所有这些咒语投射到他们的int,double,date等等。这似乎没有太大的区别。
另外,我保存每1000行使用的缩小文件
file_put_contents($fname, json_encode($reducedData));
就像我说的那样,这个剧本大约一半就会爆炸。看起来重组数据的json编码文本文件将比原始数据大50%(尽管数据少得多)。但是,这仍然意味着一个40 MB的文件,并且在使用超过120 MB后脚本的内存不足。 (我可以一次读取文件1行,但是它会突破75%而不是50%。)我认为当我读入json编码文件时,生成的数组会非常大。
现在我可以提高我允许脚本使用的内存。但是,我想知道PHP神对于为什么会发生这种情况有什么看法。阵列真的带来了那么多开销吗?有没有办法减少它?我应该遵循的任何最佳实践?