PHP读取/下载大文件时如何避免内存耗尽?
解决PHP读取/下载大文件时的内存耗尽问题
你的问题核心在于把整个文件内容都加载到内存变量中——当文件体积较大时,$content占用的内存会直接超过PHP的memory_limit限制,自然就触发了内存耗尽错误。
正确的思路:边读边输出,不缓存整个文件
我们完全不需要把文件内容全部存在内存里,而是每次读取一小段内容就直接输出到浏览器,这样内存占用始终维持在很小的范围(就是你设置的读取块大小,比如8192字节)。
优化后的代码示例:
// 先校验文件资源是否有效 if (!is_resource($file['data'])) { die("无效的文件资源,请检查文件指针"); } // 设置下载相关响应头 header("Content-Description: File Transfer"); header("Content-Disposition: attachment; filename=\"" . $file['real_filename'] . "\""); header("Content-Length: " . $file['length']); // 设置二进制流类型,兼容所有文件格式 header("Content-Type: application/octet-stream"); // 关闭PHP输出缓冲,避免缓冲累积占用内存 ob_end_flush(); // 循环读取并输出文件块 $chunkSize = 8192; // 8KB块大小,可根据需求调整为16KB/32KB,读写效率差异不大 while (!feof($file['data'])) { $chunk = fread($file['data'], $chunkSize); if ($chunk === false) { break; // 读取失败时终止循环 } echo $chunk; // 强制将缓冲内容发送到浏览器,确保下载进度实时更新 flush(); } // 关闭文件指针,释放资源 fclose($file['data']); exit;
关键优化点说明:
- 移除内存变量
$content:不再将文件内容存入内存,直接输出后丢弃,内存占用始终保持在极低水平 - 关闭输出缓冲:
ob_end_flush()关闭PHP的内置输出缓冲,避免大量内容临时存在内存中;flush()强制推送当前内容到浏览器,让用户能看到实时下载进度 - 合理的块大小:8192字节(8KB)是通用的最优值,匹配大多数操作系统的磁盘块大小,能兼顾读写效率
- 资源清理:用
fclose()主动关闭文件指针,避免不必要的资源泄漏
额外注意事项:
- 如果你的PHP配置中
output_buffering是开启状态,必须用ob_end_flush()关闭,否则即使边读边echo,内容还是会被缓冲在内存里,大文件依然可能触发内存问题 - 确保
$file['length']是准确的文件大小,这样浏览器才能正确显示下载进度 - 可以根据业务需求添加更完善的错误处理逻辑,比如读取失败时给用户返回友好提示
内容的提问来源于stack exchange,提问作者Justin
相关产品推荐
相关产品推荐

