PHP嵌套while循环仅首次执行问题求助
问题分析与解决方案
你的问题核心在于文件指针的位置:第一次执行内层while (($data2 = fgetcsv($file2)) !== FALSE)循环时,已经把$file2的文件指针移动到了文件末尾。之后每次外层循环再尝试读取$file2时,fgetcsv直接返回FALSE,所以内层循环就不再执行了。
修复方案1:每次外层循环重置文件指针
在每次进入内层循环前,用rewind()函数把$file2的指针重新移到文件开头,同时记得再次跳过首行(因为第一次读取时已经跳过,重置后需要重复操作):
header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="sample.csv"'); $output_name = md5(uniqid()) . ".csv"; $output = ROOT . "/uploads/output/" . $output_name; $fp = fopen($output, 'wb'); fputcsv($fp, array('campaign', 'spent', 'payout', 'profit', 'roi'), ','); $found_campaigns = []; fgetcsv($file1); // 跳过file1首行 while (($data = fgetcsv($file1)) !== FALSE) { array_push($found_campaigns, $data[$campaign]); echo $data[$campaign]; // 执行正常 echo "<br>"; // 检查第二个文件是否存在与第一个文件相同的campaign名称,若存在则获取payout字段并与spent字段合并 $found_in_file_2 = false; $pout = ''; // 重置file2的指针到开头,并跳过首行 rewind($file2); fgetcsv($file2); // 跳过file2首行 while (($data2 = fgetcsv($file2)) !== FALSE) { echo "Runned <br>"; if ($data2[$campaign2] == $data[$campaign]) { $found_in_file_2 = true; $pout = $data2[$payout]; // 找到匹配项后提前跳出循环,减少不必要的遍历 break; } } $pout = str_replace('$', '', $pout); $line = [ $data[$campaign], $data[$spent], $pout, $pout - $data[$spent], ($pout - $data[$spent]) / $data[$spent] ]; fputcsv($fp, $line, ','); }
修复方案2:预先读取第二个文件到数组(更高效)
如果第二个文件体积不大,推荐预先把所有数据读入数组,这样不需要每次循环都重新读取文件,性能会提升很多:
header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="sample.csv"'); $output_name = md5(uniqid()) . ".csv"; $output = ROOT . "/uploads/output/" . $output_name; $fp = fopen($output, 'wb'); fputcsv($fp, array('campaign', 'spent', 'payout', 'profit', 'roi'), ','); $found_campaigns = []; fgetcsv($file1); // 跳过file1首行 // 预先读取file2的所有数据到数组,用campaign名称作为键,方便快速查找 $file2_data = []; fgetcsv($file2); // 跳过file2首行 while (($data2 = fgetcsv($file2)) !== FALSE) { $file2_data[$data2[$campaign2]] = $data2[$payout]; } while (($data = fgetcsv($file1)) !== FALSE) { array_push($found_campaigns, $data[$campaign]); echo $data[$campaign]; // 执行正常 echo "<br>"; $pout = ''; // 直接从数组中查找匹配的campaign if (isset($file2_data[$data[$campaign]])) { $pout = $file2_data[$data[$campaign]]; echo "Runned <br>"; } $pout = str_replace('$', '', $pout); $line = [ $data[$campaign], $data[$spent], $pout, $pout - $data[$spent], ($pout - $data[$spent]) / $data[$spent] ]; fputcsv($fp, $line, ','); }
额外优化提示
- 方案1中,找到匹配的campaign后用
break跳出内层循环,避免无意义的后续遍历。 - 方案2的数组查找时间复杂度为O(1),远优于每次循环读取文件的O(n),适合处理较大的文件。
内容的提问来源于stack exchange,提问作者Prog AF
相关产品推荐
相关产品推荐

