Php 如何读取两个大文件并比较内容
我要做的是读取大文件5.6GB,大约有6亿行,第二个是16MB,有2M行 我想检查这两个文件中的重复行Php 如何读取两个大文件并比较内容,php,fopen,Php,Fopen,我要做的是读取大文件5.6GB,大约有6亿行,第二个是16MB,有2M行 我想检查这两个文件中的重复行 $wordlist = array_unique(array_filter(file('small.txt', FILE_IGNORE_NEW_LINES))); $duplicate = array(); if($file = fopen('big.txt', 'r')){ while(!feof($file)){ $lines = rtrim(fgets($file
$wordlist = array_unique(array_filter(file('small.txt', FILE_IGNORE_NEW_LINES)));
$duplicate = array();
if($file = fopen('big.txt', 'r')){
while(!feof($file)){
$lines = rtrim(fgets($file));
if(in_array($lines, $wordlist)){
echo $lines." : exists.\n";
}
}
fclose($file);
}
但这需要很长时间才能完成(它已经运行了6个小时,但尚未完成:/)
我的问题是。有没有更好的方法快速搜索大文件?我想
$wordlist=array_flip(array_unique(array_filter(file('small.txt', FILE_IGNORE_NEW_LINES))));
您在代码中实际使用的单词会减慢速度。最好只构建一次单词列表,然后自己创建:
if($file1 = fopen('big.txt', 'r')){
if($file = fopen('small.txt', 'r')){
while(!feof($file)){
$line=trim(fgets($file));
if(!isset($wordlist[$line])&&!ctype_space($line)&&!empty($line)){
$wordlist[$line]=0;
}
}
fclose($file);
}
while(!feof($file1)){
$line1 = trim(fgets($file1));
if(isset($wordlist[$line1]))
$wordlist[$line1]++;
}
fclose($file1);
}
在此步骤中,变量$wordlist包含small.txt文件中所有行的列表以及big.txt文件中每行出现的次数。
您可以使用这样的数组或对其进行过滤以删除空行。您还可以使用uasort对数组进行排序,以了解更多关于哪些行出现最多,哪些行出现较少的信息,甚至可以进一步分析…您无需调用
数组过滤器()
或数组唯一()
如果要调用array\u flip()
——它将为您消除重复项,因为在同一级别的数组中不能有重复的键
此外:
array\u unique()
array\u filter()
在清除虚假/空/空/零ish数据方面名声不好,因此我要提醒您不要使用其默认行为array\u flip()
设置非常快速的isset()
检查isset()
可能会优于array\u key\u exists()
,因为isset()
不检查null
值FILE\u SKIP\u EMPTY\u line
标记添加到FILE()
调用中,以便查找数组可能更小rtrim()
,也可能会造成一些阻力。您知道两个文件上的换行符是否一致吗?如果您可以安全地从文件()调用中删除文件
忽略
新行标志,那么您将节省六亿次调用rtrim()。或者,如果您知道跟踪big.txt行的换行符(例如,\n
?或\r\n
?),则可以将特定换行符附加到$lookup
键中——这意味着相对于大文件的每一行,准备较小文件的数据
$lookup = array_flip(file('small.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
if($file = fopen('big.txt', 'r')){
while(!feof($file)){
$line = rtrim(fgets($file));
if (isset($lookup[$line])) {
echo "$lines : exists.\n";
}
}
fclose($file);
}
快速不是PHP的特性之一。也许您可以通过不在数组()中使用
,而使用$wordlist=array\u flip($wordlist)
将单词列表元素转换为数组键,然后使用isset()
检查字符串是否在列表中来加快速度。这应该利用密钥散列来加快速度。您正在执行echo$行。“:exists。\n”代码>表示您正在输出结果。最好将这些行存储在数组中,或者存储行号,然后处理数据。第二:如果这个小列表是一本字典,那么你需要确保它们被排序。如果这是真的。。。然后,我将编写自己的函数,以根据第一个字母进行比较。在您的例子中,从大文件中取出一行,然后遍历2M行。我会找到一种方法来优化这个。。。您真的需要遍历所有这些行吗?如果您使用带有固定大小缓冲区的C,它将以您的硬盘读取文件的速度运行。@jdigital这一直是计划isset()
做了同样的事情,可能更快,因为它不是真正的函数array\u key\u exists()
不通过引用获取参数,这意味着复制字符串和更多延迟。small.txt
很小,只在程序开始时读取一次,无论您解析此文件的方式有多大的性能差异,都不会影响程序的整体性能。但是,请尝试考虑每个本机函数的内部函数。首先文件与我收集所有行的方法相同,然后array\u filter
再次循环过滤空字符串,在array unique
之后,实现复制和循环查找唯一值,最后array\u flip
也循环通过数组。想想我们所说的时间复杂度和内存使用情况……你可以根据自己的意愿对其进行否决,但PHP是一种高级语言,如果你真的知道C是如何工作的,你就会明白,或者这无关紧要。。。我只使用一个本机函数fopen来实现它…@Havenard你所说的small是指一个数组中有2百万行,因此有大约2百万个条目。你能自己尝试实现所有这些本机函数,并仔细考虑这行的全局时间复杂度和内存使用情况吗?$wordlist=array\u flip(array\u unique)(array\u filter(file('small.txt',FILE_IGNORE_NEW_line)))`……完成后请告诉我。这与PHP循环和过程不同,因为这些函数在内部用本机代码编写,所以性能永远不会匹配。正如您所说,这些函数在内部是用C编写的,逻辑在C和PHP中是相同的。算法效率的判断与lan无关基于时间复杂度和内存使用情况的语言。根据你的建议,你的建议使用的内存比我的建议少…而且如果你只使用了这些功能中的一个,你的演讲将是可以接受的,但4。。。