복붙노트

PHPExcel은 256, 512 및 1024MB의 RAM을 모두 소모합니다.

PHP

PHPExcel은 256, 512 및 1024MB의 RAM을 모두 소모합니다.

나는 그것을 이해하지 못한다. XSLX 테이블은 약 3MB이지만 1024MB의 RAM조차도 PHPExcel이 메모리에로드하기에 충분하지 않습니다.

나는 여기서 끔찍한 일을하고 있을지도 모른다.

function ReadXlsxTableIntoArray($theFilePath)
{
    require_once('PHPExcel/Classes/PHPExcel.php');
    $inputFileType = 'Excel2007';
    $objReader = PHPExcel_IOFactory::createReader($inputFileType);
    $objReader->setReadDataOnly(true);
    $objPHPExcel = $objReader->load($theFilePath);
    $rowIterator = $objPHPExcel->getActiveSheet()->getRowIterator();
    $arrayData = $arrayOriginalColumnNames = $arrayColumnNames = array();
    foreach($rowIterator as $row){
        $cellIterator = $row->getCellIterator();
        $cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
        if(1 == $row->getRowIndex ()) {
            foreach ($cellIterator as $cell) {
                $value = $cell->getCalculatedValue();
                $arrayOriginalColumnNames[] = $value;
                // let's remove the diacritique
                $value = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $value);
                // and white spaces
                $valueExploded = explode(' ', $value);
                $value = '';
                // capitalize the first letter of each word
                foreach ($valueExploded as $word) {
                    $value .= ucfirst($word);
                }
                $arrayColumnNames[] = $value;
            }
            continue;
        } else {
            $rowIndex = $row->getRowIndex();
            reset($arrayColumnNames);
            foreach ($cellIterator as $cell) {
                $arrayData[$rowIndex][current($arrayColumnNames)] = $cell->getCalculatedValue();
                next($arrayColumnNames);
            }
        }
    }
    return array($arrayOriginalColumnNames, $arrayColumnNames, $arrayData);
}

위의 함수는 Excel 테이블에서 배열로 데이터를 읽습니다.

어떤 제안?

처음에는 PHP에서 256MB RAM을 사용할 수있었습니다. 충분하지 않았습니다. 그 다음에 그 양을 두 배로 늘린 다음 1024MB를 시도했습니다. 이 오류로 인해 메모리가 여전히 부족합니다.

Fatal error: Allowed memory size of 1073741824 bytes exhausted (tried to allocate 50331648 bytes) in D:\data\o\WebLibThirdParty\src\PHPExcel\Classes\PHPExcel\Reader\Excel2007.php on line 688

Fatal error (shutdown): Allowed memory size of 1073741824 bytes exhausted (tried to allocate 50331648 bytes) in D:\data\o\WebLibThirdParty\src\PHPExcel\Classes\PHPExcel\Reader\Excel2007.php on line 688

해결법

  1. ==============================

    1.PHPExcel 포럼에서 PHPExcel의 메모리 사용에 관해 많이 쓰여졌습니다. 이전 토론을 통해 몇 가지 아이디어를 얻을 수 있습니다. PHPExcel은 스프레드 시트의 "메모리 내"표현을 유지하며 PHP 메모리 제한을 받기 쉽습니다.

    PHPExcel 포럼에서 PHPExcel의 메모리 사용에 관해 많이 쓰여졌습니다. 이전 토론을 통해 몇 가지 아이디어를 얻을 수 있습니다. PHPExcel은 스프레드 시트의 "메모리 내"표현을 유지하며 PHP 메모리 제한을 받기 쉽습니다.

    파일의 실제 크기는 거의 무의미합니다 ... 얼마나 많은 셀 (각 워크 시트의 행 * 열)이 포함되어 있는지를 아는 것이 훨씬 더 중요합니다.

    내가 항상 사용해 왔던 "경험의 법칙"은 약 1k / 셀의 평균이므로 5M 셀 통합 문서는 5GB의 메모리가 필요할 것입니다. 그러나 이러한 요구 사항을 줄일 수있는 방법은 여러 가지가 있습니다. 통합 문서 내에서 액세스해야하는 정보와이를 수행하려는 정보에 따라 이들을 결합 할 수 있습니다.

    워크 시트가 여러 개 있지만 모두로드 할 필요가없는 경우 setLoadSheetsOnly () 메서드를 사용하여 Reader가로드 할 워크 시트를 제한 할 수 있습니다. 단일 워크 시트를로드하려면 다음을 수행하십시오.

    $inputFileType = 'Excel5'; 
    $inputFileName = './sampleData/example1.xls';
    $sheetname = 'Data Sheet #2'; 
    /**  Create a new Reader of the type defined in $inputFileType  **/
    $objReader = PHPExcel_IOFactory::createReader($inputFileType);
    /**  Advise the Reader of which WorkSheets we want to load  **/ 
    $objReader->setLoadSheetsOnly($sheetname); 
    /**  Load $inputFileName to a PHPExcel Object  **/
    $objPHPExcel = $objReader->load($inputFileName);
    

    또는 이름 배열을 전달하여 setLoadSheetsOnly ()를 한 번 호출하면 여러 워크 시트를 지정할 수 있습니다.

    $inputFileType = 'Excel5'; 
    $inputFileName = './sampleData/example1.xls';
    $sheetnames = array('Data Sheet #1','Data Sheet #3'); 
    /** Create a new Reader of the type defined in $inputFileType **/ 
    $objReader = PHPExcel_IOFactory::createReader($inputFileType);
    /** Advise the Reader of which WorkSheets we want to load **/ 
    $objReader->setLoadSheetsOnly($sheetnames); 
    /**  Load $inputFileName to a PHPExcel Object  **/
    $objPHPExcel = $objReader->load($inputFileName);
    

    워크 시트의 일부만 액세스해야하는 경우 읽기 필터를 정의하여 실제로로드 할 셀을 식별 할 수 있습니다.

    $inputFileType = 'Excel5'; 
    $inputFileName = './sampleData/example1.xls';
    $sheetname = 'Data Sheet #3'; 
    
    /**  Define a Read Filter class implementing PHPExcel_Reader_IReadFilter  */ 
    class MyReadFilter implements PHPExcel_Reader_IReadFilter {
        public function readCell($column, $row, $worksheetName = '') {
            //  Read rows 1 to 7 and columns A to E only 
            if ($row >= 1 && $row <= 7) {
               if (in_array($column,range('A','E'))) { 
                  return true;
               }
            } 
            return false;
        }
    }
    
    /**  Create an Instance of our Read Filter  **/ 
    $filterSubset = new MyReadFilter(); 
    /** Create a new Reader of the type defined in $inputFileType **/ 
    $objReader = PHPExcel_IOFactory::createReader($inputFileType);
    /**  Advise the Reader of which WorkSheets we want to load 
         It's more efficient to limit sheet loading in this manner rather than coding it into a Read Filter  **/ 
    $objReader->setLoadSheetsOnly($sheetname); 
    echo 'Loading Sheet using filter';
    /**  Tell the Reader that we want to use the Read Filter that we've Instantiated  **/ 
    $objReader->setReadFilter($filterSubset); 
    /**  Load only the rows and columns that match our filter from $inputFileName to a PHPExcel Object  **/
    $objPHPExcel = $objReader->load($inputFileName);
    

    읽기 필터를 사용하면 "청크"로 통합 문서를 읽을 수 있으므로 한 번에 하나의 청크 만 메모리에 상주합니다.

    $inputFileType = 'Excel5'; 
    $inputFileName = './sampleData/example2.xls';
    
    /**  Define a Read Filter class implementing PHPExcel_Reader_IReadFilter  */ 
    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($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($inputFileName); 
        //    Do some processing here 
    
        //    Free up some of the memory 
        $objPHPExcel->disconnectWorksheets(); 
        unset($objPHPExcel); 
    }
    

    형식 정보를로드 할 필요가 없지만 워크 시트 데이터 만로드하면 setReadDataOnly () 메서드는 판독기에 셀 값을로드하고 셀 서식을 무시하도록 지시합니다.

    $inputFileType = 'Excel5';
    $inputFileName = './sampleData/example1.xls';
    /** Create a new Reader of the type defined in $inputFileType **/ 
    $objReader = PHPExcel_IOFactory::createReader($inputFileType);
    /** Advise the Reader that we only want to load cell data, not formatting **/ 
    $objReader->setReadDataOnly(true);
    /**  Load $inputFileName to a PHPExcel Object  **/
    $objPHPExcel = $objReader->load($inputFileName);
    

    셀 캐싱을 사용하십시오. 이것은 각 셀에 필요한 PHP 메모리를 줄이기위한 방법이지만 속도는 떨어집니다. 셀 객체를 압축 된 형식으로 저장하거나 PHP 메모리 (예 : 디스크, APC, memcache) 외부에 저장하면 작동하지만 메모리를 많이 저장할수록 스크립트가 더 느리게 실행됩니다. 그러나 각 셀에 필요한 메모리를 약 300 바이트로 줄일 수 있기 때문에 가상의 5M 셀에는 약 1.4GB의 PHP 메모리가 필요합니다.

    셀 캐싱은 개발자 설명서 4.2.1 절에 설명되어 있습니다.

    편집하다

    코드를 살펴보면 특별히 효율적이지 않은 반복자를 사용하고 셀 데이터 배열을 작성합니다. 이미 PHPExcel에 내장되어있는 toArray () 메소드를 살펴보고 이것을 할 수 있습니다. 행 데이터의 연관 배열을 작성하기위한 새로운 변형 메소드 인 rangeToArray ()에 대한 최근 논의를 살펴보십시오.

  2. ==============================

    2.PHPExcel과 실제로 다른 모든 라이브러리에서 동일한 메모리 문제가 발생했습니다. 마크 베이커 (Mark Baker)가 제안한대로 문제를 해결할 수도 있지만 (캐싱 작업도 가능), 메모리 문제가 시간 문제가 되었음이 드러났습니다. 읽기 및 쓰기 시간이 기하 급수적 이었기 때문에 큰 스프레드 시트의 경우 적합하지 않았습니다.

    PHPExcel과 실제로 다른 모든 라이브러리에서 동일한 메모리 문제가 발생했습니다. 마크 베이커 (Mark Baker)가 제안한대로 문제를 해결할 수도 있지만 (캐싱 작업도 가능), 메모리 문제가 시간 문제가 되었음이 드러났습니다. 읽기 및 쓰기 시간이 기하 급수적 이었기 때문에 큰 스프레드 시트의 경우 적합하지 않았습니다.

    PHPExcel과 다른 사람들은 대용량 파일을 처리하지 않기 때문에이 문제를 해결하는 라이브러리를 만들었습니다. https://github.com/box/spout에서 확인할 수 있습니다.

    희망이 도움이됩니다!

  3. ==============================

    3.PHPExcel로 작업 할 때 메모리를 적게 차지하기 위해 취할 수있는 많은 조치가 있습니다. Apache에서 서버의 메모리 제한을 수정하기 전에 다음 작업을 수행하여 메모리 사용을 최적화하는 것이 좋습니다.

    PHPExcel로 작업 할 때 메모리를 적게 차지하기 위해 취할 수있는 많은 조치가 있습니다. Apache에서 서버의 메모리 제한을 수정하기 전에 다음 작업을 수행하여 메모리 사용을 최적화하는 것이 좋습니다.

    /* Use the setReadDataOnly(true);*/
        $objReader->setReadDataOnly(true);
    
    /*Load only Specific Sheets*/
        $objReader->setLoadSheetsOnly( array("1", "6", "6-1", "6-2", "6-3", "6-4", "6-5", "6-6", "6-7", "6-8") );
    
    /*Free memory when you are done with a file*/
    $objPHPExcel->disconnectWorksheets();
       unset($objPHPExcel);
    

    아주 큰 Excel 파일을 사용하지 마십시오. 느리게 실행되고 충돌하는 파일 크기라는 것을 기억하십시오.

    getCalculatedValue ();를 사용하지 마십시오. 기능을합니다.

  4. ==============================

    4.Ypu는 PHP Excel http://ilia.ws/archives/237-PHP-Excel-Extension-0.9.1.html을 시험해 볼 수 있습니다. PHP를위한 C 확장이며 매우 빠릅니다. (PHP 구현보다 적은 메모리 사용)

    Ypu는 PHP Excel http://ilia.ws/archives/237-PHP-Excel-Extension-0.9.1.html을 시험해 볼 수 있습니다. PHP를위한 C 확장이며 매우 빠릅니다. (PHP 구현보다 적은 메모리 사용)

  5. ==============================

    5.필자의 경우 phpexcel은 항상 19999 행을 반복합니다. 아무리 많은 행이 실제로 채워 졌는지. 그래서 항상 100 행의 데이터가 메모리 오류로 끝납니다.

    필자의 경우 phpexcel은 항상 19999 행을 반복합니다. 아무리 많은 행이 실제로 채워 졌는지. 그래서 항상 100 행의 데이터가 메모리 오류로 끝납니다.

    아마도 현재 행의 셀이 비어 있고 루프를 계속 반복하면 행을 반복합니다.

  6. ==============================

    6.내 스레드를 다른 스레드에서 다시 게시하기 만하면됩니다. 계정에서 고려해야하는 Excel 스프레드 시트를 생성하거나 편집하는 서버 측 접근 방식에 대해 설명합니다. 많은 양의 데이터에 대해서는 PHPExcel 또는 ApachePOI (Java 용)와 같은 도구는 메모리 요구 사항 때문에 권장하지 않습니다. 스프레드 시트에 데이터를 주입하는 또 다른 매우 편리한 방법이 있습니다. 서버 측 생성 또는 Excel 스프레드 시트의 업데이트는 이렇게 간단한 XML 편집을 달성 할 수 있습니다. XLSX 스프레드 시트를 서버에 놓고 데이터가 dB에서 수집 될 때마다 PHP를 사용하여 압축을 풉니 다. 그런 다음 주입해야 할 워크 시트의 내용을 보유하고있는 특정 XML 파일에 액세스하여 수동으로 데이터를 삽입합니다. 그런 다음 스프레드 시트 폴더를 일반 XLSX 파일로 배포하기 위해 압축합니다. 전체 프로세스는 매우 빠르고 신뢰할 수 있습니다. 물론, XLSX / Open XML 파일의 내부 조직과 관련된 문제 및 결함은 거의 없습니다 (예 : Excel은 모든 문자열을 별도의 테이블에 저장하고 워크 시트 파일에서이 테이블에 대한 참조를 사용하는 경향이 있음). 그러나 숫자와 문자열과 같은 데이터 만 주입 할 때는 그리 어렵지 않습니다. 관심있는 사람이 있으면 코드를 제공 할 수 있습니다.

    내 스레드를 다른 스레드에서 다시 게시하기 만하면됩니다. 계정에서 고려해야하는 Excel 스프레드 시트를 생성하거나 편집하는 서버 측 접근 방식에 대해 설명합니다. 많은 양의 데이터에 대해서는 PHPExcel 또는 ApachePOI (Java 용)와 같은 도구는 메모리 요구 사항 때문에 권장하지 않습니다. 스프레드 시트에 데이터를 주입하는 또 다른 매우 편리한 방법이 있습니다. 서버 측 생성 또는 Excel 스프레드 시트의 업데이트는 이렇게 간단한 XML 편집을 달성 할 수 있습니다. XLSX 스프레드 시트를 서버에 놓고 데이터가 dB에서 수집 될 때마다 PHP를 사용하여 압축을 풉니 다. 그런 다음 주입해야 할 워크 시트의 내용을 보유하고있는 특정 XML 파일에 액세스하여 수동으로 데이터를 삽입합니다. 그런 다음 스프레드 시트 폴더를 일반 XLSX 파일로 배포하기 위해 압축합니다. 전체 프로세스는 매우 빠르고 신뢰할 수 있습니다. 물론, XLSX / Open XML 파일의 내부 조직과 관련된 문제 및 결함은 거의 없습니다 (예 : Excel은 모든 문자열을 별도의 테이블에 저장하고 워크 시트 파일에서이 테이블에 대한 참조를 사용하는 경향이 있음). 그러나 숫자와 문자열과 같은 데이터 만 주입 할 때는 그리 어렵지 않습니다. 관심있는 사람이 있으면 코드를 제공 할 수 있습니다.

  7. ==============================

    7.이 문제가 발생하여 불행히도 제안 된 솔루션 중 어느 것도 나를 도울 수 없습니다. PHPExcel에서 제공하는 기능 (수식, 조건부 스타일링 등)이 필요하므로 다른 라이브러리를 사용하는 것이 옵션이 아닙니다.

    이 문제가 발생하여 불행히도 제안 된 솔루션 중 어느 것도 나를 도울 수 없습니다. PHPExcel에서 제공하는 기능 (수식, 조건부 스타일링 등)이 필요하므로 다른 라이브러리를 사용하는 것이 옵션이 아닙니다.

    내가 결국 한 것은 개별 워크 시트를 개별 (임시) 파일로 작성한 다음이 개별 파일을 내가 작성한 특수 소프트웨어와 결합하는 것이 었습니다. 이것은 나의 메모리 소비를> 512 Mb에서 100 Mb 이하로 줄였다. 동일한 문제가 발생하면 https://github.com/infostreams/excel-merge를 참조하십시오.

  8. from https://stackoverflow.com/questions/4817651/phpexcel-runs-out-of-256-512-and-also-1024mb-of-ram by cc-by-sa and MIT license