Laravel使用maatwebsite/excel导入Excel报errno=21错误如何解决
错误原因说明
file_put_contents(): read of 8192 bytes failed with errno=21 Is a directory 错误的本质是程序尝试向路径写入内容时,该路径指向的是目录而非普通文件。在maatwebsite/excel导入大体积Excel场景下,该错误绝大多数由临时缓存目录配置错误、权限异常或大文件分块策略缺失导致。
排查步骤
- 检查maatwebsite/excel的临时缓存路径配置,确认配置值为合法的可写目录,而非文件路径
- 验证上传文件的完整性:确认php.ini的上传限制参数适配当前Excel文件大小,避免文件上传截断
- 检查Laravel storage目录的权限,确认web服务器运行用户对
storage/framework/下的子目录有读写权限 - 确认导入类是否配置了大文件分块读取逻辑,避免全量加载文件触发缓存异常
解决方案
1. 修正临时缓存目录配置
首先发布扩展的配置文件:
php artisan vendor:publish --provider="Maatwebsite\Excel\ExcelServiceProvider"
打开生成的config/excel.php文件,修改导入临时路径配置:
'import' => [ // 其他配置不变 'temporary_path' => storage_path('framework/excel_temp'), ],
手动创建对应目录并配置权限:
mkdir -p storage/framework/excel_temp chmod -R 775 storage/framework/excel_temp # 下方用户组替换为你实际的web服务器运行用户,如nginx、apache等 chown -R www-data:www-data storage/framework/excel_temp
2. 调整PHP上传与运行配置
修改php.ini配置文件,适配大文件导入需求:
; 单文件上传上限调整为大于你的Excel文件大小 upload_max_filesize = 100M ; POST请求体上限匹配上传大小 post_max_size = 100M ; 内存限制适配分块读取需求 memory_limit = 256M ; 脚本最大执行时间调整为足够完成导入 max_execution_time = 300
修改完成后重启web服务与php-fpm服务生效。
3. 开启分块导入降低资源占用
修改你的UsersImport导入类,实现WithChunkReading接口开启分块处理:
<?php namespace App\Imports; use Maatwebsite\Excel\Concerns\ToModel; use Maatwebsite\Excel\Concerns\WithChunkReading; class UsersImport implements ToModel, WithChunkReading { // 原有导入逻辑保持不变 /** * 定义分块大小,可根据服务器配置调整为500-2000区间 */ public function chunkSize(): int { return 1000; } }
4. 优化控制器导入逻辑
调整控制器代码,增加文件有效性校验,避免路径解析错误:
public function importData(Request $request) { try { $file = $request->file('file'); if (!$file->isValid()) { throw new \Exception('上传文件不合法,请重新上传'); } Excel::import(new UsersImport, $file->getRealPath()); return redirect()->back()->with('success', 'Record Imported Successfully'); }catch (\Exception $e){ // 开发环境可打开下方注释打印异常堆栈方便排查 // dd($e->getMessage(), $e->getTraceAsString()); return redirect()->back()->with('error', $e->getMessage()); } }
内容的提问来源于stack exchange,提问作者Ch Bilal Ahmed
相关产品推荐
相关产品推荐

