ながさわさんのアレグロモデラート

アレグロモデラート(Allegro moderato)は、速さを示す演奏記号で「穏やかに速く」

Apache POI でつくった 200,000 × 255 の .xlsx ファイルを Microsoft Excel 2010 で開く

Excel は 2007 から、ワークシートの最大サイズが 1,048,576 × 16384 になったので、Apache POI で大きな .xlsx ファイルを作ってみる。

Apache POI の プロジェクトサイトから、POI のバイナリーをダウンロードする。
Apache POI - Download Release Artifacts

つづけて、SXSSF の How-To にあるサンプルコードを参考に 200,000 × 255 くらいで実行してみる。
The New Halloween Document

package poitest;

import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

public class Main {

    public static void main(String[] args) throws Throwable {
        SXSSFWorkbook wb = new SXSSFWorkbook(1); // keep 100 rows in memory, exceeding rows will be flushed to disk
        Sheet sh = wb.createSheet();
        for(int rownum = 0; rownum < 200000; rownum++){
        	if ( (rownum+1) % 1000 == 0 ){
        		System.out.println( rownum + 1 );
        	}
            Row row = sh.createRow(rownum);
            for(int cellnum = 0; cellnum < 255; cellnum++){
                Cell cell = row.createCell(cellnum);
                String address = new CellReference(cell).formatAsString();
                cell.setCellValue(address);
            }

        }

        FileOutputStream out = new FileOutputStream("c:/data/sxssf.xlsx");
        wb.write(out);
        out.close();

        // dispose of temporary files backing this workbook on disk
        wb.dispose();
    }
}

20分も待てば、232M の .xlsx ファイルができあがる。
(XSSF だと、オンメモリ処理で、メモリを大量に食いつぶすので、SXSSF じゃないとだめ。)

さて、これを開けたときの結果。

1.Excel 2010 32ビット

早々に、「'sxssf.xlsx' には読み取れない内容が含まれています。このブックの内容を回復しますか? ブックの発行元が信頼出来る場合は、[はい] をクリックしてください。」

と言ってくれ、「はい」すると、回復を試みる。うまくいけば、開くときもあるが、「リソース不足のため、このタスクを完了することができません。選択するデータを少なくするか、ほかのアプリケーションを終了して再度試してください。」

と出て「まいった」となる。

2.Excel 2013 32ビット

f:id:lakeside_shinnosuke:20160429191207p:plain

がんばって、開けようとするが、しばらくすると、

f:id:lakeside_shinnosuke:20160429191240p:plain

このように「まいった」と言うのだが、2010 のときと違い、64 ビットで開けたら開くかもよ、と言ってくれる。なので、

3.Excel 2010 64ビット

で開くと、
f:id:lakeside_shinnosuke:20160429192115p:plain

10分以上、もくもくと開こうとする。

f:id:lakeside_shinnosuke:20160429192411p:plain

その間、メモリはゆるやかな右肩上がり。

そして、

f:id:lakeside_shinnosuke:20160429192021p:plain

やったー。開きました。


非常に大きい .xlsx を Apache POI でつくるとき、次のような問題にぶちあたっていく。

  • .xls の API である HSSF に対応する .xlsx の API である XSSF を使うと遅い。(zip 展開しながらだから。)
  • XSSF はオンメモリなので、ありったけのメモリが使われる
  • POI 3.8 beta3 から利用できる SXSSF という API を使えば少ないメモリで .xlsx を作成できるが、Buffered Streaming に特化したものなので、大きなテンポラリファイルが作られテンポラリに書き出し済みの行へ戻ってセルの書き込みができない
  • ただし、SXSSF のテンポラリファイルは設定によって、gzip で圧縮しながらテンポラリを作ることもできる。
  • テンポラリファイルへの書き込み行数も設定できるので、この値を大きくしておけば、前に戻ることもできるようだ。(これは未確認。)

このように紆余曲折を経て、大きい .xlsx ファイルが、小さなリソースと、短い時間で作られることになるのだが、いざ、クライアントから開けようと思うと、32 ビットではでかすぎて開けられない、ということらしい。
そのうえ、32 ビット Excel で開くことができるファイルの具体的な制限というのは、どんなにググっても、適切な記述が出てこない。

強いて言えば、以下の URL の「データ モデル ブックのメモリ ストレージとファイル サイズの最大制限」
support.office.com

32 ビット環境の仮想アドレス空間は 2 ギガバイト (GB) で、Excel やブック、また同じプロセスで実行するアドインで共有されます。データ モデルのアドレス空間のシェアは 500 ~ 700 メガバイト (MB) まで増やすことができますが、他のモデルやアドインが読み込まれている場合は少なくなることがあります。
64 ビット環境では、ファイル サイズに対し、ハード制限はありません。ブックのサイズは、利用可能メモリとシステム リソースでのみ制限されます。
注: データ モデルにテーブルを追加すると、ファイル サイズが増大します。多数のデータ ソースやデータ型をブック内で使って複雑なデータ モデル関係を作るつもりではない場合、テーブル、ピボット テーブル、データ接続をインポートまたは作成するときに、[このデータをデータ モデルに追加する] ボックスをオフにします。
詳細については、「データ モデルの仕様と制限」を参照してください。

これはようするに、.xlsx が zip 展開 されたときに、2GB を超えているときに、32ビット Excel では、オンメモリに展開できない、と言っているようだ。いずれにしても、64 ビットで開けられたので、32ビットでは 232M はでかすぎる、ということだろう。

おわり。