面试题:
有两个文件文件,大小都超过了1G,一行一条数据,每行数据不超过500字节,两文件中有一部分内容是完全相同的,请写代码找到相同的行,并写到新文件中。PHP最大允许内内为256M。
解题步骤
遇到此问题,首先先尝试从小范围解决,比如题目中,要求查找两个文件相同的行,那么我们可以先读取文件到内存中(数组),然后通过array_intersect()函数获取两个数组的交集,即为相同的行,此时,小范围的问题已经找到解决方法了。
再回到问题本身,两个文件都超过1G,PHP最大使用内存是256M(也有可能是128M,甚至10M,这不用担心),在此条件下,直接读取文件到内存,显然不可行,我们可以考虑使用split命令将其分割成若干个小文件,再运用上面的思路逐个对比小文件,得到的结果,再合并到结果集里面,然后再去重,即得到题目要求。
步骤一、通过php生成两个大容量数据文件
<?php
function build_file($max)
{
$file1 = fopen("/tmp/file1.txt", "w");
$file2 = fopen("/tmp/file2.txt", "w");
for($i =0; $i < $max; $i++) {
$text1 = md5(microtime() . rand(100, 999)) . "\r\n";
$text2 = md5(microtime() . rand(100, 999)) . "\r\n";
fwrite($file1, $text1);
fwrite($file2, $text2);
}
fclose($file1);
fclose($file2);
return true;
}
//同时生成两个拥有100万行测试数据的文本文件
build_file(1000000);
步骤二、通过split命令分割数据文件为若干个小文件
mkdir /tmp/split1
mkdir /tmp/split2
cd /tmp/split1
split -l 10000 /tmp/file1.txt
cd /tmp/split2
split -l 10000 /tmp/file2.txt
ll -h /tmp/split1/
total 33M
-rw-r--r-- 1 root root 333K Jul 8 17:18 xaa
-rw-r--r-- 1 root root 333K Jul 8 17:18 xab
-rw-r--r-- 1 root root 333K Jul 8 17:18 xac
-rw-r--r-- 1 root root 333K Jul 8 17:18 xad
-rw-r--r-- 1 root root 333K Jul 8 17:18 xae
-rw-r--r-- 1 root root 333K Jul 8 17:18 xaf
-rw-r--r-- 1 root root 333K Jul 8 17:18 xag
-rw-r--r-- 1 root root 333K Jul 8 17:18 xah
-rw-r--r-- 1 root root 333K Jul 8 17:18 xai
-rw-r--r-- 1 root root 333K Jul 8 17:18 xaj
-rw-r--r-- 1 root root 333K Jul 8 17:18 xak
......
步骤三、编写具体实现逻辑
<?php
ini_set("memory_limit", "128m");
//读取文件内容到数组
function read($file, $max = 0)
{
$rows = [];
$handle = fopen($file, "r");
while(!feof($handle)) {
$rows[] = fgets($handle, 1024);
}
fclose($handle);
return $rows;
}
//遍历某个路径,读取所有文件名
function read_dir($dir)
{
$files = [];
$handle = opendir($dir);
while(false !== ($file = readdir($handle))) {
if ($file == '.' || $file == '..') continue;
$files[] = $dir . $file;
}
closedir($handle);
return $files;
}
$dir1 = "/tmp/split1/";
$dir2 = "/tmp/split2/";
$files1 = read_dir($dir1);
$files2 = read_dir($dir2);
$result = [];
//遍历子文件,分别对比,获取子文件交集,再merge结果
foreach ($files1 as $f1) {
$data1 = read($f1);
foreach ($files2 as $f2) {
$data2 = read($f2);
$retval = [];
$retval = array_intersect($data1, $data2);
if (array_values($retval)[0] !== false){
$result = array_merge($result, $retval);
}
}
}
var_dump(array_unique($result));
die;
面对超过1G的大文件,使用PHP在内存限制256M的情况下找出两文件的相同行。通过split命令分割文件,然后用PHP逐个对比小文件,利用array_intersect()获取交集,最终合并结果并去重。
1624

被折叠的 条评论
为什么被折叠?



