Excel POI Ver3.17
セル結合情報は「sheet.getMergedRegions()」で取得できます
セル結合の削除は「sheet.removeMergedRegion(index)」で出来ます。
(削除すると内部が減るので、再取得、またはIndexの大きいほうから消すこと)
セル結合の追加は「sheet.addMergedRegion(CellRangeAddress)」で出来ます。
普通に考えたら、削除時だけ注意すればそんなに難しくないのですが…
これがめちゃくちゃ遅い。超遅い。死ぬほど遅い…
約20000件のデータを下記例のフォーマットでエクセルに出力する時…1時間以上かかりました…
【No、発生日時、種類、対象、内容】の各入力欄をセル結合する人が多いのかなぁと思ってます。(私はそうでした)
その場合、POIで行う場合、下記ソースの様に「行追加→スタイルのコピー→罫線追加→値の追加」の順番になると思います
その場合、「this.sheet.addMergedRegion(address);」処理が遅いです。
例の画像の場合、1行に対して上記処理を5回行います。それが遅すぎるようです。
ちなみに、十分な行を先に作成しておいても、削除する場合は同じです。追加・削除はほぼ同じ時間が掛ります。
逆に言えば、想定行数が決まっている場合、そこからの差分のセル結合量が少なければ、問題無いと思います。
で、この遅さはいかんともしがたい!セル結合の処理を行わなければいいのだ!
どのように対策したか…「選択範囲内で中央」です。
セル結合の操作をしなければ良いので、「中央揃え」を「選択範囲内で中央」に変更します。
そうすることで、無事に中央揃えが出来ます。データは右に増える分は常に見えています。(右揃えはダメだった気が…)
というわけで、下記で実装しました。
スタイルが指定されている行のセル分ループし、コピー先のセルにスタイルをコピーします。
注意点は「選択範囲内で中央」で使用するセル全てに「HorizontalAlignment.CENTER_SELECTION」を設定することです
こうすることで、セル結合を行わずに、中央ぞろえ、罫線等のスタイルがコピーされます。(workbook.createCellStyle() を行っていない事に注意)
if分の部分は仕様に合わせて変更してあげてください。
こうすることで、
約20000件のデータを出力した場合…約4~5秒で終わりました!
驚異的スピードです
というわけで、ExcelのTemplateにデータ出力はいろんな場面で使用されると思います。
が、行数が未定のデータを「中央揃え」にする場合「選択範囲内で中央」を使用し、セル結合・解除を可能な限り処理しない様に工夫しましょう。
もちろん、セル結合をPOIを使って増減させなければ速度に影響はありません。
また、2万行をセル結合の状態で作るのと、今回の方法で作るのと、実際にWindowsのExcel で開く時間も段違いです。
私のPCでエクセルを実行した場合…
セル結合したエクセルファイルは 5秒前後かかりました。
セル結合無しのエクセルファイルは 1秒未満でした。
(POIで開くときも遅いです)
というわけで、実際のExcelでもセル結合はやめた方が良いですね。
いや…早くなって良かった…
しかし、セル結合しない中央揃えって、嫌われるんだよな…orz
蛇足ですが、workbook.createCellStyle() は6000個ぐらいで例外が発生しました。同じスタイルを使う場合は作らずにコピーで良いです
Tomcat:8.0.53
Java:1.8.0_191
POI:3.17
検索用:Apache POI Excel 遅い 使えない 速度 改善 早く セル結合 セル結合解除 スタイル 中央 揃え 選択範囲内で中央
セル結合情報は「sheet.getMergedRegions()」で取得できます
セル結合の削除は「sheet.removeMergedRegion(index)」で出来ます。
(削除すると内部が減るので、再取得、またはIndexの大きいほうから消すこと)
セル結合の追加は「sheet.addMergedRegion(CellRangeAddress)」で出来ます。
普通に考えたら、削除時だけ注意すればそんなに難しくないのですが…
これがめちゃくちゃ遅い。超遅い。死ぬほど遅い…
約20000件のデータを下記例のフォーマットでエクセルに出力する時…1時間以上かかりました…
【No、発生日時、種類、対象、内容】の各入力欄をセル結合する人が多いのかなぁと思ってます。(私はそうでした)
その場合、POIで行う場合、下記ソースの様に「行追加→スタイルのコピー→罫線追加→値の追加」の順番になると思います
// 反映元行を取得 final Row srcRow = CellUtil.getRow(copySrcIndex, this.sheet); // 反映先行を取得 final Row destRow = CellUtil.getRow(copyDestIndex, this.sheet); final CellRangeAddress address = new CellRangeAddress(destRow.getRowNum(), destRow.getRowNum(), 1, 2); RegionUtil.setBorderTop(BorderStyle.THIN, address, this.sheet); RegionUtil.setBorderRight(BorderStyle.THIN, address, this.sheet); RegionUtil.setBorderBottom(BorderStyle.THIN, address, this.sheet); RegionUtil.setBorderLeft(BorderStyle.THIN, address, this.sheet); this.sheet.addMergedRegion(address); // これが曲者… final Cell noCell = CellUtil.getCell(destRow, 1); final CellStyle noStyle = this.wb.createCellStyle(); noStyle.cloneStyleFrom(srcRow.getCell(1).getCellStyle()); noStyle.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex()); noStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); noCell.setCellStyle(noStyle); noCell.setCellValue(srcRow.getCell(1).getStringCellValue());
その場合、「this.sheet.addMergedRegion(address);」処理が遅いです。
例の画像の場合、1行に対して上記処理を5回行います。それが遅すぎるようです。
ちなみに、十分な行を先に作成しておいても、削除する場合は同じです。追加・削除はほぼ同じ時間が掛ります。
逆に言えば、想定行数が決まっている場合、そこからの差分のセル結合量が少なければ、問題無いと思います。
で、この遅さはいかんともしがたい!セル結合の処理を行わなければいいのだ!
どのように対策したか…「選択範囲内で中央」です。
セル結合の操作をしなければ良いので、「中央揃え」を「選択範囲内で中央」に変更します。
そうすることで、無事に中央揃えが出来ます。データは右に増える分は常に見えています。(右揃えはダメだった気が…)
というわけで、下記で実装しました。
スタイルが指定されている行のセル分ループし、コピー先のセルにスタイルをコピーします。
注意点は「選択範囲内で中央」で使用するセル全てに「HorizontalAlignment.CENTER_SELECTION」を設定することです
// 反映元行を取得 final Row srcRow = CellUtil.getRow(copySrcIndex, this.sheet); // 反映先行を取得 final Row destRow = CellUtil.getRow(copyDestIndex, this.sheet); for (int colIndex = srcRow.getFirstCellNum(); colIndex < srcRow.getLastCellNum(); colIndex++) { final CellStyle srcCellStyle = CellUtil.getCell(srcRow, colIndex).getCellStyle(); if (colIndex < 19) { // 対象より左のセルは選択範囲の中央揃えとする srcCellStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION); } CellUtil.getCell(destRow, colIndex).setCellStyle(srcCellStyle); }
こうすることで、セル結合を行わずに、中央ぞろえ、罫線等のスタイルがコピーされます。(workbook.createCellStyle() を行っていない事に注意)
if分の部分は仕様に合わせて変更してあげてください。
こうすることで、
約20000件のデータを出力した場合…約4~5秒で終わりました!
驚異的スピードです
というわけで、ExcelのTemplateにデータ出力はいろんな場面で使用されると思います。
が、行数が未定のデータを「中央揃え」にする場合「選択範囲内で中央」を使用し、セル結合・解除を可能な限り処理しない様に工夫しましょう。
もちろん、セル結合をPOIを使って増減させなければ速度に影響はありません。
また、2万行をセル結合の状態で作るのと、今回の方法で作るのと、実際にWindowsのExcel で開く時間も段違いです。
私のPCでエクセルを実行した場合…
セル結合したエクセルファイルは 5秒前後かかりました。
セル結合無しのエクセルファイルは 1秒未満でした。
(POIで開くときも遅いです)
というわけで、実際のExcelでもセル結合はやめた方が良いですね。
いや…早くなって良かった…
しかし、セル結合しない中央揃えって、嫌われるんだよな…orz
蛇足ですが、workbook.createCellStyle() は6000個ぐらいで例外が発生しました。同じスタイルを使う場合は作らずにコピーで良いです
Tomcat:8.0.53
Java:1.8.0_191
POI:3.17
検索用:Apache POI Excel 遅い 使えない 速度 改善 早く セル結合 セル結合解除 スタイル 中央 揃え 選択範囲内で中央