使用Flysystem ZipArchiveAdapter打包千级文件时内存耗尽问题求助
我之前也碰到过一模一样的问题——用Flysystem的ZipArchiveAdapter处理上千张图片打包时,内存直接耗尽报错,当时只能覆盖1000张以内的用户请求,后来折腾出几个靠谱的解决办法,分享给你:
改用流式写入,避免全量加载文件到内存
问题根源其实是默认的处理逻辑会把每个文件的内容先读进PHP内存,再写入ZIP,上千张图堆起来内存肯定扛不住。换成流式操作就好多了:初始化适配器后,用writeStream方法直接把源文件的流写入ZIP,每个文件只会占用少量缓冲区内存,不会累积所有内容。代码大概是这样:$zipAdapter = new ZipArchiveAdapter($zipPath); foreach ($userImages as $image) { // 打开源文件的读流 $sourceStream = fopen($image->getRealPath(), 'rb'); // 直接写入ZIP,不缓存到内存 $zipAdapter->writeStream($image->getFilename(), $sourceStream); // 记得关闭流释放资源 fclose($sourceStream); }直接用PHP原生ZipArchive类手动处理
如果Flysystem的封装还是有内存开销,不如直接用原生的ZipArchive。它的addFile方法可以直接传入文件路径,ZipArchive会自己从磁盘读取文件写入归档,完全不用把文件内容加载到PHP内存里,内存占用极低。示例代码:$zip = new ZipArchive(); if ($zip->open($outputZipPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) === true) { foreach ($userImages as $image) { // 第一个参数是本地文件路径,第二个是归档里的文件名 $zip->addFile($image->getRealPath(), $image->getFilename()); } $zip->close(); }这种方式我处理过万级别的文件都没出过内存问题,亲测有效。
分批打包+合并归档(极端场景用)
如果你的文件数量多到离谱(比如几万张),可以考虑分批次打包:每处理500-1000张就生成一个临时ZIP,最后再把这些临时ZIP里的文件逐个转移到最终归档里,处理完一批就删除临时ZIP释放磁盘空间。不过这个方法稍显繁琐,一般前两种方法就能解决问题,实在不行再用这个。临时调整内存限制(过渡方案)
要是你需要快速临时缓解问题,可以在脚本开头加ini_set('memory_limit', '512M');或者更高的数值,但这只是治标不治本,文件数量再往上走还是会爆内存,只能作为过渡用。
另外还要注意:处理完后及时关闭所有打开的流、清理临时文件,避免内存泄漏;如果是Web环境,记得设置足够的脚本执行时间,比如set_time_limit(0);(仅限允许修改的环境)。
内容的提问来源于stack exchange,提问作者user1015149

