2013年3月5日火曜日

POIの実装の選択肢

Apache POI といえば、言わずと知れたJavaでExcelを扱うための便利なライブラリ。
Excelを扱ういろんなJavaのライブラリやツールが存在するが、内部はPOIでした。
なんてことが良くあるくらい鉄板ライブラリ。

POIは、ツールで利用する程度の実装ならあまり気にしないが、
とても多くのメモリを消費する。
それは、実ファイルサイズの10〜20倍くらいまで飛躍する。
また、Office2007以降のExcelファイルを扱う場合にとても顕著に現れる。

なので、本番システムでPOIを利用する場合には、メモリ問題に意識を置く必要がある。
(本番システムでPOIを使うのはどうかと思うが、仕方ない場合)


POIには、大きく2つのモデルが存在する。
以降の話はOffice2007を前提とする。

◆ユーザモデル
 ユーザモデルは、ExcelのBookを丸ごと読み込んでマクロ感覚で扱える。
 一般的にググって出てくるネタは大抵がこのユーザモデルの場合が多い。
 このユーザモデルは、Excelを丸ごと読み込むってところで
 大量のメモリを消費してしまう。
 そのかわりとても簡易的なコードで分かりやすく扱えるメリットを持つ。

◆イベントモデル
 イベントモデルは、Excelの情報をシート単位でメモリ上にあげて処理を行える。
 これは、Office2007をZIP解凍したことのある人はすぐにピンとくるだろうが、
 シート毎に別れているXMLを読んでいる訳である。
 従って、内部ではXMLの解析となる。
 
 イベントモデルは、メモリの消費量を抑えるためのものであるため
 当然ながらXMLの解析はSAXで行う。

 XSSFReaderというクラスがSAXパーサとして公開されており、
 1セルごとのイベントをユーザがハンドリングするためのインタフェースを
 インナークラスとして定義している。
 従って、ユーザはこのインナークラスを実装したコンテンツハンドラを実装する。
 
 ただ、日本で使用する場合には注意点がある。
 POI(3.8)で確認した時に、漢字を読み込むと以下のように取得される事象があった。

 Excel上の文字列:「亜」
 POIで読み込んだ文字列:「亜ア」
 
 これは、バグでSharedStringTableという辞書みたいなXMLに記載されている
 マルチバイトの文字列で東アジア圏内の発音のために用意されているタグを
 POIが意識していないためである。

 この事象を修正するには、自分でSharedStringTableのパーサを修正するか、
 POIのバグFix版を使うしかないだろう。


上記が、いわゆる2大処理方式となる。
その他に、書き込み限定で利用できるストリーミングユーザモデルというものもある。
これについては、また別の機会に書く事にする。