2016-04-14 17 views
6

im bằng cách sử dụng PHPExcel để đọc các tệp .xls. Tôi khá một thời gian ngắn tôi gặpĐọc tệp .xls qua PHPExcel ném Lỗi nghiêm trọng: cho phép kích thước bộ nhớ ... ngay cả với trình đọc đoạn

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

sau khi một số googling, tôi đã cố gắng chunkReader để ngăn chặn điều này (được đề cập ngay cả trên trang chủ PHPExcel), nhưng vẫn bị mắc kẹt với lỗi này.

Suy nghĩ của tôi là, thông qua trình đọc đoạn, tôi sẽ đọc từng phần một phần và bộ nhớ của tôi sẽ không tràn. Nhưng phải có một số bộ nhớ nghiêm trọng? Hoặc im giải phóng một số bộ nhớ xấu? Tôi thậm chí đã cố nâng ram máy chủ lên 1GB. Kích thước tập tin, mà tôi cố gắng để đọc là khoảng 700k, mà không phải là quá nhiều (im cũng đọc ~ 20MB pdf, xlsx, docx, doc, vv tập tin mà không có vấn đề). Vì vậy, tôi giả sử có thể chỉ là một số troll nhỏ tôi bỏ qua.

Mã trông như thế này

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

Và đây là mã cho 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; 
    } 
} 

Trả lời

4

Vì vậy, tôi tìm thấy giải pháp thú vị ở đây How to read large worksheets from large Excel files (27MB+) with PHPExcel?

như Phụ lục 3 trong câu hỏi

edit1: cũng với giải pháp này, tôi đã đến điểm nút với thông điệp errr yêu thích của tôi, nhưng tôi tìm thấy một cái gì đó về bộ nhớ đệm, vì vậy tôi thực hiện điều này

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

thời gian gần đây tôi đã thử nghiệm nó chỉ cho các tập tin xls ít hơn 10MB, nhưng nó có vẻ như để làm việc (còn tôi đặt $objReader->setReadDataOnly(true);) và nó có vẻ như cân bằng, đủ để đạt được tốc độ và bộ nhớ đồng nsumption. (tôi sẽ theo con đường gai góc của tôi nhiều hơn, nếu có thể)

edit2: Vì vậy, tôi đã thực hiện thêm một số nghiên cứu và tìm thấy trình đọc đoạn không cần thiết theo cách của tôi. Vì vậy, câu trả lời cuối cùng của tôi cho câu hỏi của tôi là một cái gì đó như thế, mà đọc tập tin .xls (chỉ dữ liệu từ các tế bào, mà không hình thành, thậm chí lọc ra công thức). Khi tôi sử dụng cache_tp_php_temp im khả năng đọc file xls (thử nghiệm đến 10MB) và khoảng 10k hàng và nhiều cột trong vài giây và không có vấn đề bộ nhớ

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

đây là những gì tôi đã làm dựa trên ví dụ của bạn. Tôi phát hiện ra rằng một số biến với công cụ php cần phải được thiết lập để đảm bảo sự thành công của hàm. Hãy xem này. Tôi loại bỏ một số phần để chèn vào cơ sở dữ liệu của tôi nhưng ý tưởng chính là ở đây.

$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); 
Các vấn đề liên quan