1.问题描述
现在有一个总表staff.xls,每一行代表一个人的数据,要求将该表转换为若干个表people.xls,每一个人为一个表。或者问题反过来,要求将若干个表汇总。
2.思路
将问题简单化,仔细想想,也就几个步骤:
(0)我们知道staff.xls和people.xls的格式布局,知道两个表转换时数据是怎样对应的,比如staff的‘BS’对应people的‘D3’等 (这个需要人工写成数组)。
(1)加载总表staff.xls,将数据以行为单位读取到数组中。
(2)加载模板people.xls表,将数组中的数据按照对应格式写入表格,保存到相应的路径。
ps:phpExcel常用方法可以自己在搜搜,我这里也转载了一篇:phpExcel常用方法
3.遇到的问题
(1)图片的大小处理,phpExcel只提供图片等比例缩放的函数,如$objDrawing->setWidth()、$objDrawing->setHeight()等,根据需要,我查看了源码"Classes\PHPExcel\Worksheet\BaseDrawing.php",自己增加了单独设置高度和宽度的函数。
// function added by myself
public function setWidthOnly($pValue = 0) {
// Resize proportional? // Set width
if ($this->_resizeProportional) {
$this->_width = $pValue;
}
return $this;
}
public function setHeightOnly($pValue = 0) {
// Resize proportional? Set height
if ($this->_resizeProportional) {
$this->_height = $pValue;
}
return $this;
}
(2)总表太大,500*60个单元格左右,运行一会后会报超内存问题。
phpExcel内存消耗过大是一个比较常见的问题,很多人问道,网上也有很多解答的方案,绝大多数要么没说清楚要么说的没用,各大网站也爬来爬去= =这种现象真的很不好,这里我来整理一下找到的比较好的方法。方法3、4非常有效,建议4种结合起来用。
<1>开大内存时间限制。
ini_set('max_execution_time','0'); // 设置时间上限为不限时间
ini_set('memory_limit', '512M'); // 设置内存
<2>设置缓存。
参考:点击打开链接
我采取的方法是:
// 设置缓存模式为序列化模式
$cacheMethod =PHPExcel_CachedObjectStorageFactory::cache_in_memory_serialized;
PHPExcel_Settings::setCacheStorageMethod($cacheMethod);
<3>及时释放内存
这里要注意一点,phpExcel自己对内存释放做的不是很好,需要我们及时手动调用他提供的函数来释放内存。
在函数中也要手动调用来释放。
$objPHPExcel->disconnectWorksheets(); //及时手动释放内存资源
unset($objPHPExcel);
<4>表格过大,分批读取,每次只读取固定行,不必要的列不用读取,如果不关心格式,只读取数据。
参考:点击打开链接
方法是自己实现一个类来读取表格,每次只读取固定行,分批读取
class chunkReadFilter implements PHPExcel_Reader_IReadFilter
{
private $_startRow = 0;
private $_endRow = 0;
/** Set the list of rows that we want to read */
public function setRows($startRow, $chunkSize) {
$this->_startRow = $startRow;
$this->_endRow = $startRow + $chunkSize;
}
public function readCell($column, $row, $worksheetName = '') {
// Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) {
return true;
}
return false;
}
}
/** Create a new Reader of the type defined in $inputFileType **/
$objReader = PHPExcel_IOFactory::createReader('Excel5');
/** Define how many rows we want to read for each "chunk" **/
$chunkSize = 20;
/** Create a new Instance of our Read Filter **/
$chunkFilter = new chunkReadFilter();
/** Tell the Reader that we want to use the Read Filter that we've Instantiated **/
$objReader->setReadFilter($chunkFilter);
/** Loop to read our worksheet in "chunk size" blocks **/
/** $startRow is set to 2 initially because we always read the headings in row #1 **/
for ($startRow = 2; $startRow <= 600; $startRow += $chunkSize) {
/** Tell the Read Filter, the limits on which rows we want to read this iteration **/
$chunkFilter->setRows($startRow,$chunkSize);
/** Load only the rows that match our filter from $inputFileName to a PHPExcel Object **/
$objPHPExcel = $objReader->load('test2.xls');
// Do some processing here
// Free up some of the memory
$objPHPExcel->disconnectWorksheets();
unset($objPHPExcel);
}