8

XLS ファイルを処理するときに、PHPExcel でメモリの問題が発生しています。非常に大きなファイル (50k ~ 200k 行、9 ~ 10 列) を扱う必要があるため、ReadFilters を使用してメモリの問題を解決する必要がありました。

ただし、XLSX ファイルではかなりうまく機能しましたが、バックグラウンド プロセスとチャンク サイズのいくつかの簡単な計算を組み合わせて使用​​しましたが、XLS ファイルでは機能しませんでした。

これは、すべてが爆発するコードです。

Class ExcelReadFilter implements PHPExcel_Reader_IReadFilter
{
    private $startRow = 0;
    private $endRow = 0;

    public function setRows($startRow, $chunkSize) {
        $this->startRow    = $startRow;
        $this->endRow        = $startRow + $chunkSize;
    }

    public function readCell($column, $row, $worksheetName = '') {
        if ( ($row >= $this->startRow && $row < $this->endRow) ) {
            return true;
        }
        return false;
    }
}

PHPExcel_Settings::setCacheStorageMethod( PHPExcel_CachedObjectStorageFactory::cache_in_memory_serialized );

....
$filter = new ExcelReadFilter();
$filter->setRows($desde, $cuantas);

$reader = PHPExcel_IOFactory::createReader($this->file_type);   

$reader->setLoadSheetsOnly($sheet_name);    
$reader->setReadDataOnly(false);    
$reader->setReadFilter($filter);

$chunk = $reader->load($this->file);
$chunk->setActiveSheetIndexByName($sheet_name);

$active_sheet = $chunk->getActiveSheet();
$rowIterator = $active_sheet->getRowIterator($desde);
$this->num_filas = $active_sheet->getHighestRow();

その直後に、何が起こっているのかをよりよく理解するために、次の行を含めました。

ob_start();
var_dump($rowIterator);

$f = fopen("excel-info.txt", "w");
fwrite($f, ob_get_clean());
fclose($f);

ob_end_clean();
die;

そして、メモリの問題がどこにあるかを指摘していると思います。元の XLS ファイルを最初にアップロードしたとき、excel-info.txt のサイズは 13M でした。次に、XLS ファイルを開いて XLSX として保存し、プロセスを繰り返したところ、excel-info.txt は 285k しかありませんでした。

これらのフィルターを変更して XLS ファイルを操作する方法はありますか?

ああ、PHP メモリ制限をより高い値に設定することはオプションではありませんが、実行時間は重要ではありません。

追加した

さまざまなメモリ キャッシュ オプションを使用すると、メモリ使用量を十分に削減して機能させることができ、ほとんどの場合、許容可能なサイズに維持できました。

現在、私は PHPExcel_CachedObjectStorageFactory::cache_to_sqlite を使用していますが、それで十分なようです。

ファイルに入れられたシリアル化された情報に対して行った計算が間違っていたことに注意してください。Excel5 ファイルは、フィルタ条件を満たさないすべての値が NULL に設定されている Excel ファイルの行と同じ数のレコードを持つ配列を生成します。もちろん、テキストファイルに保存すると、次のようなものになります...

array(10) {
  ["A"]=>
  NULL
  ["B"]=>
  NULL
  ["C"]=>
  NULL
  ["D"]=>
  NULL
  ["E"]=>
  NULL
  ["F"]=>
  NULL
  ["G"]=>
  NULL
  ["H"]=>
  NULL
  ["I"]=>
  NULL
  ["J"]=>
  NULL
} 

...ファイルには多くのスペースが必要ですが、php_memory には必要ないので、それは私のせいです。

今、私はこのコードを使用してメモリ使用量を追跡しています:

for ( $i=1; $i < 20000; $i+=5000 ){
        $filter->setRows($i, 5000);
        echo "\n1- Usage: ".(memory_get_usage ()/1024)/1024;
        $objPHPExcel = $reader->load($this->file);
        echo "\n2- Usage: ".(memory_get_usage ()/1024)/1024;
        $sheetData = $objPHPExcel->getActiveSheet()->toArray(null,true,true,true);
        unset($sheetData);
        unset($objPHPExcel);
        echo "\n3- Usage: ".(memory_get_usage ()/1024)/1024;
        }

特定の XLS ファイルでは、次のように表示されます。

最初の反復 1- 使用法: 4.3859634399414 2- 使用法: 34.292671203613 3- 使用法: 34.68034362793

2 回目の反復 1- 使用法: 34.68034362793 2- 使用法: 34.68293762207 3- 使用法: 34.684982299805

XLSX として保存した後の同じファイル:

最初の反復 1- 使用法: 4.2780990600586 2- 使用法: 6.9042129516602 3- 使用法: 7.2916641235352

2 回目の反復 1- 使用法: 7.2916641235352 2- 使用法: 7.5115432739258 3- 使用法: 7.2813568115234

ただし、XLSX として保存するとサイズが約半分になるため、これがバグなのか予期された動作なのかはわかりません。

4

2 に答える 2