2016-04-14 12 views
6

ich mit PHPExcel, um .xls-Dateien zu lesen. Ich eine ganz kurze Zeit iLesen .xls-Datei über PHPExcel wirft Fataler Fehler: zulässige Speichergröße ... sogar mit Chunk-Reader

Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 730624 bytes) in Excel\PHPExcel\Shared\OLERead.php on line 93 

nach einigen googeln treffen, i chunkReader versucht, dies (auch auf PHPExcel Homesite erwähnt) zu verhindern, aber im noch mit diesem Fehler stucked.

Mein Gedanke ist, dass via Chunk-Reader, ich werde Datei für Teil lesen und mein Speicher wird nicht überlaufen. Aber es muss ein ernstes Erinnerungsdefizit geben? Oder befreie ich etwas Speicher? Ich habe sogar versucht, Server-RAM auf 1 GB zu erhöhen. Dateigröße, die ich versuche zu lesen ist etwa 700k, die nicht so viel ist (ich lese auch ~ 20MB pdf, xlsx, docx, doc, etc Dateien ohne Problem). Also nehme ich an, dass es nur einen kleinen Troll geben kann, den ich übersehen habe.

Code wie folgt aussieht

function parseXLS($fileName){ 
    require_once dirname(__FILE__) . './sphider_design/include/Excel/PHPExcel/IOFactory.php'; 
    require_once dirname(__FILE__) . './sphider_design/include/Excel/PHPExcel/ChunkReadFilter.php'; 

    $inputFileType = 'Excel5'; 

    /** Create a new Reader of the type defined in $inputFileType **/ 
    $objReader = PHPExcel_IOFactory::createReader($inputFileType); 
    /** 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 <= 65536; $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($fileName); 
     // Do some processing here 

     // Free up some of the memory 
     $objPHPExcel->disconnectWorksheets(); 
     unset($objPHPExcel); 
    } 
} 

Und hier ist der Code für chunkReader

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; 
    } 
} 

Antwort

4

So fand ich interessante Lösung hier How to read large worksheets from large Excel files (27MB+) with PHPExcel?

als Addendum 3 in Frage

edit1: Auch mit dieser Lösung kam ich mit meiner Lieblings-errr Nachricht an Nadelöhr, aber ich fand etwas über Caching, so i dies

$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp; 
$cacheSettings = array(' memoryCacheSize ' => '8MB'); 
PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings); 
implementiert

vor kurzem ich es nur für xls-Dateien weniger als 10 MB getestet, aber es scheint, wie zu arbeiten (i gesetzt auch $objReader->setReadDataOnly(true);) und es scheint, wie ausgewogen genug Geschwindigkeit und Speicher gemeinsam zu erreichen nsumption. (ich werde meinem dornigen Weg mehr folgen, wenn es möglich ist)

edit2: Also machte ich ein paar weitere Recherchen und fand Chunk Reader in meiner Art unnötig. (Scheint mir ähnlich, Speicherproblem ist dasselbe mit Chunk-Reader und ohne es.) Also meine endgültige Antwort auf meine Frage ist so etwas, das .xls-Datei liest (nur Daten aus Zellen, ohne Formatierung, sogar Ausfiltern von Formeln). Wenn ich cache_tp_php_temp im der Lage, verwenden xls-Dateien zu lesen (zu 10 MB getestet) und etwa 10 k Zeilen und mehrere Spalten in wenigen Sekunden und ohne Memory-Ausgabe

function parseXLS($fileName){ 

/** PHPExcel_IOFactory */ 
    require_once dirname(__FILE__) . './sphider_design/include/Excel/PHPExcel/IOFactory.php'; 
    require_once dirname(__FILE__) . './sphider_design/include/Excel/PHPExcel/ChunkReadFilter.php'; 
    require_once dirname(__FILE__) . './sphider_design/include/Excel/PHPExcel.php'; 

    $inputFileName = $fileName; 
    $fileContent = ""; 

    //get inputFileType (most of time Excel5) 
    $inputFileType = PHPExcel_IOFactory::identify($inputFileName); 

    //initialize cache, so the phpExcel will not throw memory overflow 
    $cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp; 
    $cacheSettings = array(' memoryCacheSize ' => '8MB'); 
    PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings); 

    //initialize object reader by file type 
    $objReader = PHPExcel_IOFactory::createReader($inputFileType); 

    //read only data (without formating) for memory and time performance 
    $objReader->setReadDataOnly(true); 

    //load file into PHPExcel object 
    $objPHPExcel = $objReader->load($inputFileName); 

    //get worksheetIterator, so we can loop sheets in workbook 
    $worksheetIterator = $objPHPExcel->getWorksheetIterator(); 

    //loop all sheets 
    foreach ($worksheetIterator as $worksheet) {  

      //use worksheet rowIterator, to get content of each row 
      foreach ($worksheet->getRowIterator() as $row) { 
       //use cell iterator, to get content of each cell in row 
       $cellIterator = $row->getCellIterator(); 
       //dunno 
       $cellIterator->setIterateOnlyExistingCells(false);  

       //iterate each cell 
       foreach ($cellIterator as $cell) { 
        //check if cell exists 
        if (!is_null($cell)) { 
         //get raw value (without formating, and all unnecessary trash) 
         $rawValue = $cell->getValue(); 
         //if cell isnt empty, print its value 
         if ((trim($rawValue) <> "") and (substr(trim($rawValue),0,1) <> "=")){ 
          $fileContent .= $rawValue . " ";            
         } 
        } 
       }  
      }  
    } 

    return $fileContent; 
} 
0

hier ist, was ich tat, basierend auf Ihre Beispiele. Ich fand heraus, dass einige Variablen mit der PHP-Engine gesetzt werden müssen, um den Erfolg der Funktion sicherzustellen. Schau dir das an. Ich entferne ein Teil, um es in meine Datenbank einzufügen, aber die Grundidee ist hier.

$upload_dir = dirname(__DIR__) . "/uploads/"; 
$inputFileName = $upload_dir . basename($_FILES["fileToUpload"]["name"]); 
$insertOk = FALSE; 

// get inputFileType (most of time Excel5) 
$inputFileType = PHPExcel_IOFactory::identify($inputFileName); 

// initialize cache, so the phpExcel will not throw memory overflow 
ini_set('memory_limit', '-1'); 
ini_set('max_execution_time', 180); // 180 seconds of execution time maximum 
$cacheMethod = PHPExcel_CachedObjectStorageFactory::cache_to_phpTemp; 
$cacheSettings = array(' memoryCacheSize ' => '8MB'); 
PHPExcel_Settings::setCacheStorageMethod($cacheMethod, $cacheSettings); 

// initialize object reader by file type 
$objReader = PHPExcel_IOFactory::createReader($inputFileType); 

// read only data (without formating) for memory and time performance 
$objReader->setReadDataOnly(true); 

// load file into PHPExcel object 
$objPHPExcel = $objReader->load($inputFileName); 
$objPHPExcel->setActiveSheetIndex(0); 

$spreadsheetInfo = $objReader->listWorksheetInfo($inputFileName); 
$maxRowsAllowed = $spreadsheetInfo[0]['totalRows']; 

// Define how many rows we want to read for each "chunk" 
$chunkSize = 200; 

// Create a new Instance of our Read Filter 
$chunkFilter = new ReportChunkReadFilter(); 

// 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 = 0; $startRow <= $maxRowsAllowed; $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($inputFileName); 
    $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true); 

    // loop on the rows of the filtered excel file (the chunk) 
    foreach ($sheetData as $rowArray) {          
     echo $rowArray['A']; 
     // do your stuff here 
    } 

    // Free up some of the memory 
    $objPHPExcel->disconnectWorksheets(); 
    unset($objPHPExcel);      
} 

unlink($inputFileName); 
Verwandte Themen