PHP不会将完整文件读入数组,只有部分
Posted
技术标签:
【中文标题】PHP不会将完整文件读入数组,只有部分【英文标题】:PHP won't read full file into array, only partial 【发布时间】:2019-01-03 00:16:03 【问题描述】:我有一个包含 3,200,000 行 csv 数据(450 列)的文件。总文件大小为 6 GB。
我是这样读取文件的:
$data = file('csv.out');
没有失败,它只读取 897,000 行。我用'print_r'和echo sizeof($data)
确认。我将“memory_limit”增加到了一个荒谬的值,例如 80 GB,但没有任何作用。
现在,它确实读入了我的另一个大文件,行数相同 (3,200,000),但只有几列,因此总文件大小为 1.1 GB。所以这似乎是一个总文件大小问题。仅供参考,$data 数组中的 897,000 行大约是 1.68 GB。
更新:我将第二个(更长的)文件增加到 2.1 GB(超过 500 万行),它可以很好地读取它,但将另一个文件截断为 1.68 GB。所以看起来不是大小问题。如果我继续将第二个文件的大小增加到 2.2 GB,而不是截断它并继续执行程序(就像对第一个文件所做的那样),它会死掉并转储核心。
更新:我通过打印整数和浮点数验证了我的系统是 64 位的:
<?php
$large_number = 2147483647;
var_dump($large_number); // int(2147483647)
$large_number = 2147483648;
var_dump($large_number); // float(2147483648)
$million = 1000000;
$large_number = 50000 * $million;
var_dump($large_number); // float(50000000000)
$large_number = 9223372036854775807;
var_dump($large_number); //
int(9223372036854775807)
$large_number = 9223372036854775808;
var_dump($large_number); //
float(9.2233720368548E+18)
$million = 1000000;
$large_number = 50000000000000 * $million;
var_dump($large_number); // float(5.0E+19)
print "PHP_INT_MAX: " . PHP_INT_MAX . "\n";
print "PHP_INT_SIZE: " . PHP_INT_SIZE . " bytes (" . (PHP_INT_SIZE * 8) . " bits)\n";
?>
这个脚本的输出是:
int(2147483647)
int(2147483648)
int(50000000000)
int(9223372036854775807)
浮点数(9.2233720368548E+18)
浮点数(5.0E+19)
PHP_INT_MAX:9223372036854775807
PHP_INT_SIZE:8 字节(64 位)
既然它是 64 位的,而且内存限制设置得非常高,为什么 PHP 不读取大于 2.15 GB 的文件?
【问题讨论】:
1) 您确定需要阅读整个文件吗?你能把你的任务分成小部分并逐行读取文件吗? 2)您可以逐行读取文件并将这些行存储到SplDoublyLinkedList
或SplFixedArray
而不是默认数组以减少RAM需求。
与其将整个文件读入内存,我建议使用像fgetcsv()
这样的文件指针函数
至于你的问题,很遗憾我找不到任何关于file()
的具体限制的参考资料,但你会认为它受到可用内存容量的限制。
这是一个拥有大量内存的巨大服务器。不过我得试试你的建议。似乎每个文件都有内存限制,因为我将“memory_limit”提高到如此巨大的值,问题仍然存在。
我将它读入内存的原因是它必须做一个巨大的嵌套循环。我必须将 320 万行中的每一行与其他 320 万行进行比较。所以不确定上面的替代方法是否会像记忆一样快?如果是这样,我会尝试。否则,我可能不得不用 C 重写整个内容:-(
【参考方案1】:
想到的一些事情:
如果您使用的是 32 位 PHP,则无法读取大于 2GB 的文件。 如果读取文件时间过长,可能会出现超时。 如果文件真的很大,那么将其全部读入内存将会有问题。通常最好读取数据块并对其进行处理,除非您需要随机访问文件的所有部分。 另一种方法(我过去曾使用过)是将大文件分割成更小、更易于管理的文件(例如,如果它是简单的日志文件,应该可以使用)【讨论】:
它是 64 位 PHP。读取文件只需要大约 15 秒。【参考方案2】:我修好了。我所要做的就是改变我阅读文件的方式。为什么……我不知道。
旧代码只能读取 6.0 GB 中的 2.15 GB:
$data = file('csv.out');
读取完整 6.0 GB 的新代码:
$data = array();
$i=1;
$handle = fopen('csv.out');
if ($handle)
while (($data[$i] = fgets($handle)) !== false)
// process the line read
$i++;
请随意解释原因。使用时一定有一定的限制
$var=file();
有趣的是,2.15 GB 接近我读到的 32 位限制。
【讨论】:
以上是关于PHP不会将完整文件读入数组,只有部分的主要内容,如果未能解决你的问题,请参考以下文章