应采用逐行或分块读取方式避免内存溢出:一、fopen+feof逐行读;二、stream_get_line按分隔符读块;三、SplFileObject迭代器;四、临时调高memory_limit并配流上下文;五、fread分块读二进制。

如果您尝试使用PHP读取大文件,但脚本执行过程中出现内存耗尽、Fatal error: Allowed memory size exhausted 错误,则说明当前读取方式一次性将全部内容载入内存。以下是解决此问题的步骤:
一、使用fopen配合fgets逐行读取
该方法避免将整个文件加载进内存,仅在每次循环中读取一行内容,适用于按行处理的日志、CSV等文本文件。
1、使用fopen以只读模式打开文件,获取文件指针资源。
2、在while循环中调用fgets函数,每次读取一行(含换行符),直到返回false为止。
立即学习“PHP免费学习笔记(深入)”;
3、对每行内容进行处理,例如解析、过滤或写入数据库,处理完毕后立即释放该行变量引用。
4、循环结束后调用fclose关闭文件指针。
二、使用stream_get_line配合自定义分隔符
当文件不以标准换行符分隔,或需按特定标记(如空行、分段标识)读取时,stream_get_line可替代fgets实现更灵活的块读取,仍保持低内存占用。
1、使用fopen打开文件并获取流资源。
2、调用stream_get_line函数,传入流资源、最大长度和自定义分隔字符串(如"\n\n"表示双换行)。
3、判断返回值是否为空字符串或false以决定是否继续读取。
4、每次获取到一个逻辑块后立即处理,不缓存历史块数据。
三、使用SplFileObject迭代器
SplFileObject是PHP内置的面向对象式文件操作类,支持seek、key、current等迭代器方法,天然支持foreach遍历且内存友好,底层同样逐行读取。
1、实例化SplFileObject对象,传入文件路径作为构造参数。
2、设置setFlags(SplFileObject::READ_AHEAD | SplFileObject::SKIP_EMPTY | SplFileObject::DROP_NEW_LINE)以提升效率并忽略空行与换行符。
3、使用foreach遍历对象,每次迭代自动调用fgets读取一行,$line变量即为当前行内容。
4、在循环体内完成业务逻辑,无需手动管理指针或判断EOF。
四、使用memory_limit临时调整与流上下文控制
在确保安全前提下,可对单次脚本执行动态放宽内存限制,并结合流上下文参数防止缓冲区过度膨胀,适用于需短暂提升处理能力的场景。
1、在脚本开头调用ini_set('memory_limit', '512M'),注意该设置仅对当前请求生效,不可设为-1。
2、使用stream_context_create创建上下文,设置'php' => ['max_execution_time' => 0]和'http' => ['timeout' => 0]等必要参数。
3、将上下文传入fopen或file_get_contents(仅限较小增量读取)等函数调用中。
4、执行完毕后应尽快恢复原始memory_limit值,避免影响其他脚本。
五、分块读取+substr/fread组合
对于无需按行解析的二进制或固定格式文件(如图片头信息提取、日志切片),可设定固定字节块大小,使用fread分批读入并处理,彻底规避行解析开销。
1、使用fopen打开文件,获取资源句柄。
2、计算文件总大小,通过filesize()获取,并初始化偏移量$offset = 0。
3、在while循环中调用fread($handle, $chunkSize),每次读取指定字节数(如8192),读取结果为空字符串则退出循环。
4、对当前块内容执行二进制处理逻辑,完成后unset($chunk)显式释放内存。










