Apache POIでスタイルを作りすぎると開けないExcelファイルが出来てしまう
Apache POI とは
Java 向けの Excel ファイル操作ライブラリです。xls/xlsx 両対応。
公式サイトはこちら https://poi.apache.org
.NET 版の NPOI もあり、ほぼ同じ構成なので同じように当てはまる事象と思われます。
前提として
POI のセルのスタイルの設定方法については以下の Qiita を読んで下さい、
Apache POI でセルスタイルを設定すると他のセルにまで適用される
そもそも開けない Excel とは
POI で帳票を作成する際に、セルの罫線などの書式を CellStyle というクラスで扱いますが
これは、Workbook(ワークブック=xls(x)ファイルそのもの)の所有物です。
上記の通り、createStyle すれば新しいスタイルを作って、セルに適用できるのですが、
ワークブック内のスタイルの数には制限があります。
- xls の場合 4000 個くらい
- xlsx の場合 64000 個
Excel の仕様および制限 - Excel
で、これを超えるとファイルを開く際に Excel がエラーを表示してファイルが開けなくなります。
で、何が問題なのか
workbook.createCellStyle(); するとスタイルが一個作成されます。
例えば、セルの色が黄色なセルが 5000 個あって、全てのセルで毎回 createCellStyle() すると
開けない.xls が出来上がってしまいます。
#この場合、上記の Qiita の最初の通り、Style のインスタンスを使い回せば何の問題もありません
スタイルのパターンが少ない場合は Style のインスタンスを使い回しする方法でなんとかなりますが、例えば、テンプレートファイルがあって、そこに色を付ける処理をする際は、セルごとに Style を生成するしかありません。そして、色を付けるセルが 4000 を超えると、またしても開けない.xls のできあがりになります。
ではどうするか
セルのスタイルが同じである場合は、CellStyle のインスタンスを使い回すようにして下さい。
・・・。
なんて事をいちいち書いてたら納期遅れか徹夜一直線です。
POI の開発チームは親切にも対策を用意してくれています。
CellUtil.setCellStyleProperty()
です
// 普通に書くとこうなりますが、これだとスタイルが必ず新しく作られてしまう
CellStyle cellStyle = cell.getCellStyle();
CellStyle newStyle = workbook.createCellStyle();
newStyle.cloneStyleFrom(cellStyle);
style.setFillPattern(CellStyle.SOLID_FOREGROUND);
style.setFillForegroundColor(IndexedColors.YELLOW.getIndex());
cell.setCellStyle(newStyle);
// CellUtil#setCellStylePropertyを使えば、同一スタイルをdistinctしてくれます!
CellUtil.setCellStyleProperty(cell, book, CellUtil.FILL_PATTERN, CellStyle.SOLID_FOREGROUND);
CellUtil.setCellStyleProperty(cell, book, CellUtil.FILL_FOREGROUND_COLOR, IndexedColors.YELLOW.getIndex());
まとめ
CellUtil にはこれ以外にも、getRow()など便利なメソッドがあります。
#素の sheet.getRow()は row がないと null が返るが、このメソッドは自動で新規作成してくれると言うより、個人的見解ですが・・・
POI の *Util(CellUtil 以外にもいくつかあります) にメソッドがある操作は、そっちを使った方が幸せになれます。
#というか、落とし穴おおすぎー
Discussion