PHPOffice/PHPExcel官方已经不维护,推荐使用PHPOffice/PhpSpreadsheet
本文使用类库版本:1.10
Composer安装:composer require phpoffice/phpspreadsheet:^1.10
Excel2003版最大行数是65536行
Excel2007开始的版本最大行数是1048576行
本机环境:CentOS7.9、PHP7.4.12、3G内存
运行模式:CLI
测试样本:40万行记录,大小144M
问题1:单次导入内存溢出
解决方法:解除PHP运行时内存限制,ini_set('memory_limit', 0);
问题2:导入时间长
以测试文件为例,内存占用最多达到2.7G
导入文件(不含业务操作)耗时60秒
问题3:循环导入多个文件,内存占用持续升高
解决方法:单文件读取结束及时释放内存
查看当前内存使用情况:
考虑方案:按行读取
CSV是文本文件,用记事本就能打开,可以做到按行读取
XLS 是二进制的文件只能用 EXCEL 才能打开,所以推荐使用CSV格式
参考网址:https://www.oschina.net/question/187489_2163581
PhpSpreadsheet处理CSV方式:fopen、fgets、fgetcsv,没有实现按指定行数读取
分析:
如果客户机器内存空间小,有几种方案
以时间换空间:
设置指定行数循环读取,
弊端:需要修改PhpSpreadsheet类库源码
以速度换空间:
PhpSpreadsheet在工作表中平均每个单元格使用约1k,因此大型工作簿可以迅速用尽可用内存。单元缓存提供了一种机制,该机制允许PhpSpreadsheet在较小的内存或非内存(例如,在磁盘上,APCu,内存缓存或Redis、Memcache中)中维护单元对象。这使您可以减少大型工作簿的内存使用量,尽管以访问单元数据的速度为代价。
存在弊端,以Redis为例:
自定义缓存必须实现Psr\SimpleCache\CacheInterface接口,yii2-redis类库无法直接使用
代码示例
实现了Redis、File缓存的使用,可参考:composer require inkime/phpspreadsheetcache
PhpSpreadsheet的实现方式:每个单元格记录缓存,以测试文件为例,40万行、14个单元格/行,总共会生成14x40万个缓存文件,耗时太长难以接受
结论:机器内存不足情况下,优先考虑拆开多个CSV文件,其次使用第三方Redis服务器,最次是File缓存写入磁盘