読者です 読者をやめる 読者になる 読者になる

日曜プログラミング

休日趣味でやってるプログラミング関連記事をダラダラと

Excel の制限で書式は 4000 までしか指定できない

Clojure+docjure を使って 7000 行くらいのデータを Excel に書きだそうとしたら以下の例外が出た。

Exception in thread "main" java.lang.IllegalStateException: The maximum number of cell styles was exceeded. 
You can define up to 4000 styles in a .xls workbook at org.apache.poi.hssf.usermodel.HSSFWorkbook.createCellStyle(HSSFWorkbook.java:1120)

調べると POI と言うより Excel のそもそもの制限みたい。

Excel 2003 でまさに 4000 まで、2007 でも拡張されたが 64000 までとか。
http://support.microsoft.com/kb/213904/ja

回避するには CellStyle オブジェクト作って使い回すべしとの事らしい。
そもそもの Excel の制限から言えばまあ妥当な話か。

ただ docjure でも add-row! の中では createCell を呼んでいてそれはいいのだが、
スタイルを使い回す部分が見当たらないし Cell オブジェクト作る時にスタイル挟み込むよう
な関数が見当たらず。

Java/POI にするか docjure を修正になるがどっちもめんどくさ。

[2013/04/20 追記]
これ書き出す時のデータに日付型が含まれているので add-row!(add-rows!) すると
日付型を書き出す時に新たに CellStyle オブジェクトを毎回作ってるのが直接の原因だった。

docjure ソースの該当コード↓

(defn apply-date-format! [cell format]
  (let [workbook (.. cell getSheet getWorkbook)
        date-style (.createCellStyle workbook) ; ← ここ
        format-helper (.getCreationHelper workbook)]
    (.setDataFormat date-style
                    (.. format-helper createDataFormat (getFormat format)))
    (.setCellStyle cell date-style))) 

こいつは add-row! から呼び出され、add-rows! は add-row! を doseq で回してる実装になっており、結果毎回 CellStyle オブジェクトが作られ、簡単に書式制限 4000 に引っかかってた。多分 4000 行じゃなくて 4000 セル分超えたらエラーになるんじゃなかろうか。

add-row(s)! なり apply-date-format! の定義を書き換えればとも思ったが、読み込んだライブラリの定義を上書きする方法を知らないので、書き出し時は日付型を使わない形で回避。