From 5af4355b7865e1bf61d019e19e5555cfd65e07c7 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Wed, 20 Oct 2010 11:30:09 +0000 Subject: [PATCH] New examples, including reading a larger workbook in chunks to give improved memory usage git-svn-id: https://phpexcel.svn.codeplex.com/svn/trunk@62489 2327b42d-5241-43d6-9e2a-de5ac946f064 --- .../Examples/Reader/exampleReader11.php | 69 +++++++++---- .../Examples/Reader/exampleReader12.php | 91 +++++++++++------- .../Examples/Reader/exampleReader13.php | 32 ++++-- .../Examples/Reader/exampleReader14.php | 73 ++++++++++++++ .../Examples/Reader/exampleReader15.php | 46 +++++++++ .../Examples/Reader/sampleData/example2.xls | Bin 0 -> 36864 bytes 6 files changed, 246 insertions(+), 65 deletions(-) create mode 100644 Documentation/Examples/Reader/exampleReader14.php create mode 100644 Documentation/Examples/Reader/exampleReader15.php create mode 100644 Documentation/Examples/Reader/sampleData/example2.xls diff --git a/Documentation/Examples/Reader/exampleReader11.php b/Documentation/Examples/Reader/exampleReader11.php index c1c1fc5..becdb63 100644 --- a/Documentation/Examples/Reader/exampleReader11.php +++ b/Documentation/Examples/Reader/exampleReader11.php @@ -16,7 +16,7 @@ date_default_timezone_set('Europe/London');

PHPExcel Reader Example #11

-

Simple File Reader for Multiple CSV Files

+

Reading a Workbook in "Chunks" Using a Configurable Read Filter (Version 1)

'; -$objPHPExcel = $objReader->load($inputFileName); -$objPHPExcel->getActiveSheet()->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME)); -foreach($inputFileNames as $sheet => $inputFileName) { - echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' into WorkSheet #',($sheet+2),' using IOFactory with a defined reader type of ',$inputFileType,'
'; - $objReader->setSheetIndex($sheet+1); - $objReader->loadIntoExisting($inputFileName,$objPHPExcel); - $objPHPExcel->getActiveSheet()->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME)); + +/** Define a Read Filter class implementing PHPExcel_Reader_IReadFilter */ +class chunkReadFilter implements PHPExcel_Reader_IReadFilter +{ + private $_startRow = 0; + + private $_endRow = 0; + + /** We expect a list of the rows that we want to read to be passed into the constructor */ + public function __construct($startRow, $chunkSize) { + $this->_startRow = $startRow; + $this->_endRow = $startRow + $chunkSize; + } + + public function readCell($column, $row, $worksheetName = '') { + // Only read the heading row, and the rows that were configured in the constructor + if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) { + return true; + } + return false; + } } +echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' using IOFactory with a defined reader type of ',$inputFileType,'
'; +/** Create a new Reader of the type defined in $inputFileType **/ +$objReader = PHPExcel_IOFactory::createReader($inputFileType); + + echo '
'; -echo $objPHPExcel->getSheetCount(),' worksheet',(($objPHPExcel->getSheetCount() == 1) ? '' : 's'),' loaded

'; -$loadedSheetNames = $objPHPExcel->getSheetNames(); -foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { - echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,'
'; - $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); + +/** Define how many rows we want for each "chunk" **/ +$chunkSize = 20; + +/** Loop to read our worksheet in "chunk size" blocks **/ +for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) { + echo 'Loading WorkSheet using configurable filter for headings row 1 and for rows ',$startRow,' to ',($startRow+$chunkSize-1),'
'; + /** Create a new Instance of our Read Filter, passing in the limits on which rows we want to read **/ + $chunkFilter = new chunkReadFilter($startRow,$chunkSize); + /** Tell the Reader that we want to use the new Read Filter that we've just Instantiated **/ + $objReader->setReadFilter($chunkFilter); + /** Load only the rows that match our filter from $inputFileName to a PHPExcel Object **/ + $objPHPExcel = $objReader->load($inputFileName); + + // Do some processing here + $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); var_dump($sheetData); - echo '
'; + echo '

'; } diff --git a/Documentation/Examples/Reader/exampleReader12.php b/Documentation/Examples/Reader/exampleReader12.php index 82c2c23..7011355 100644 --- a/Documentation/Examples/Reader/exampleReader12.php +++ b/Documentation/Examples/Reader/exampleReader12.php @@ -1,6 +1,9 @@ @@ -13,60 +16,74 @@ include_once('../baseIncludes.php');

PHPExcel Reader Example #12

-

Simple File Reader for Tab-Separated Value File using the Advanced Value Binder

+

Reading a Workbook in "Chunks" Using a Configurable Read Filter (Version 2)

_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; + } +} + + +echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' using IOFactory with a defined reader type of ',$inputFileType,'
'; +/** Create a new Reader of the type defined in $inputFileType **/ $objReader = PHPExcel_IOFactory::createReader($inputFileType); -echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' into WorkSheet #1 using IOFactory with a defined reader type of ',$inputFileType,'
'; -$objReader->setDelimiter("\t"); -$objPHPExcel = $objReader->load($inputFileName); -$objPHPExcel->getActiveSheet()->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME)); echo '
'; -echo $objPHPExcel->getSheetCount(),' worksheet',(($objPHPExcel->getSheetCount() == 1) ? '' : 's'),' loaded

'; -$loadedSheetNames = $objPHPExcel->getSheetNames(); -foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { - echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,' (Formatted)
'; - $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); + +/** 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 **/ +for ($startRow = 2; $startRow <= 240; $startRow += $chunkSize) { + echo 'Loading WorkSheet using configurable filter for headings row 1 and for rows ',$startRow,' to ',($startRow+$chunkSize-1),'
'; + /** 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($inputFileName); + + // Do some processing here + $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); var_dump($sheetData); - echo '
'; + echo '

'; } -echo '
'; - -foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { - echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,' (Unformatted)
'; - $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); - $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,false,true); - var_dump($sheetData); - echo '
'; -} - -echo '
'; - -foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { - echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,' (Raw)
'; - $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); - $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,false,false,true); - var_dump($sheetData); - echo '
'; -} ?> diff --git a/Documentation/Examples/Reader/exampleReader13.php b/Documentation/Examples/Reader/exampleReader13.php index 1b0bfa5..9c9d903 100644 --- a/Documentation/Examples/Reader/exampleReader13.php +++ b/Documentation/Examples/Reader/exampleReader13.php @@ -16,7 +16,7 @@ date_default_timezone_set('Europe/London');

PHPExcel Reader Example #13

-

Handling Loader Exceptions using Try/Catch

+

Simple File Reader for Multiple CSV Files

'; -try { - $objPHPExcel = PHPExcel_IOFactory::load($inputFileName); -} catch(Exception $e) { - die('Error loading file "',pathinfo($inputFileName,PATHINFO_BASENAME),'": ',$e->getMessage()); +$inputFileType = 'CSV'; +$inputFileNames = array('./sampleData/example1.csv','./sampleData/example2.csv'); + +$objReader = PHPExcel_IOFactory::createReader($inputFileType); +$inputFileName = array_shift($inputFileNames); +echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' into WorkSheet #1 using IOFactory with a defined reader type of ',$inputFileType,'
'; +$objPHPExcel = $objReader->load($inputFileName); +$objPHPExcel->getActiveSheet()->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME)); +foreach($inputFileNames as $sheet => $inputFileName) { + echo 'Loading file ',pathinfo($inputFileName,PATHINFO_BASENAME),' into WorkSheet #',($sheet+2),' using IOFactory with a defined reader type of ',$inputFileType,'
'; + $objReader->setSheetIndex($sheet+1); + $objReader->loadIntoExisting($inputFileName,$objPHPExcel); + $objPHPExcel->getActiveSheet()->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME)); } echo '
'; -$sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); -var_dump($sheetData); +echo $objPHPExcel->getSheetCount(),' worksheet',(($objPHPExcel->getSheetCount() == 1) ? '' : 's'),' loaded

'; +$loadedSheetNames = $objPHPExcel->getSheetNames(); +foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { + echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,'
'; + $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); + var_dump($sheetData); + echo '
'; +} ?> diff --git a/Documentation/Examples/Reader/exampleReader14.php b/Documentation/Examples/Reader/exampleReader14.php new file mode 100644 index 0000000..f8661b8 --- /dev/null +++ b/Documentation/Examples/Reader/exampleReader14.php @@ -0,0 +1,73 @@ + + + + + +PHPExcel Reader Example #14 + + + + +

PHPExcel Reader Example #14

+

Simple File Reader for Tab-Separated Value File using the Advanced Value Binder

+'; +$objReader->setDelimiter("\t"); +$objPHPExcel = $objReader->load($inputFileName); +$objPHPExcel->getActiveSheet()->setTitle(pathinfo($inputFileName,PATHINFO_BASENAME)); + + +echo '
'; + +echo $objPHPExcel->getSheetCount(),' worksheet',(($objPHPExcel->getSheetCount() == 1) ? '' : 's'),' loaded

'; +$loadedSheetNames = $objPHPExcel->getSheetNames(); +foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { + echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,' (Formatted)
'; + $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); + var_dump($sheetData); + echo '
'; +} + +echo '
'; + +foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { + echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,' (Unformatted)
'; + $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,false,true); + var_dump($sheetData); + echo '
'; +} + +echo '
'; + +foreach($loadedSheetNames as $sheetIndex => $loadedSheetName) { + echo 'Worksheet #',$sheetIndex,' -> ',$loadedSheetName,' (Raw)
'; + $objPHPExcel->setActiveSheetIndexByName($loadedSheetName); + $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,false,false,true); + var_dump($sheetData); + echo '
'; +} + +?> + + \ No newline at end of file diff --git a/Documentation/Examples/Reader/exampleReader15.php b/Documentation/Examples/Reader/exampleReader15.php new file mode 100644 index 0000000..c507b8a --- /dev/null +++ b/Documentation/Examples/Reader/exampleReader15.php @@ -0,0 +1,46 @@ + + + + + +PHPExcel Reader Example #15 + + + + +

PHPExcel Reader Example #15

+

Handling Loader Exceptions using Try/Catch

+'; +try { + $objPHPExcel = PHPExcel_IOFactory::load($inputFileName); +} catch(Exception $e) { + die('Error loading file "',pathinfo($inputFileName,PATHINFO_BASENAME),'": ',$e->getMessage()); +} + + +echo '
'; + +$sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); +var_dump($sheetData); + + +?> + + \ No newline at end of file diff --git a/Documentation/Examples/Reader/sampleData/example2.xls b/Documentation/Examples/Reader/sampleData/example2.xls new file mode 100644 index 0000000000000000000000000000000000000000..9e24c36cb18665745d98caac65c855fe899d7480 GIT binary patch literal 36864 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 literal 0 HcmV?d00001