POIで行コピーを行う (Apache POI Tips)

2021年6月1日火曜日

Java POI

t f B! P L

Apache POIで、行のコピーを行う方法を紹介します。

いきなり残念なお知らせですが、Apache POIには行コピーを行うメソッドは用意されていません。

面倒ですが、行の内容を取得して、その中のセルの値およびスタイルをコピーするという方法しかないようです。

POIで行コピーを行う のイメージ

スポンサーリンク

サンプルコード

さっそく、行のコピーを行うサンプルコードを、紹介したいと思います。

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.*;

/**
 * POIで行をコピーする処理
 * @param workbook ワークブック
 * @param worksheet ワークシート
 * @param sourceRowNum コピー元の行インデックス
 * @param destinationRowNum コピー先の行インデックス
 */
private static void copyRow(Workbook workbook, Sheet worksheet, int sourceRowNum, int destinationRowNum) {
  Row newRow = worksheet.getRow(destinationRowNum);
  Row sourceRow = worksheet.getRow(sourceRowNum);

  if (newRow != null) {
    //コピー先に行が既に存在する場合、1行下にずらす
    worksheet.shiftRows(destinationRowNum, worksheet.getLastRowNum(), 1);
    newRow = worksheet.createRow(destinationRowNum);
  } else {
    //存在しない場合は作成
    newRow = worksheet.createRow(destinationRowNum);
  }

  // セルの型、スタイル、値などをすべてコピーする
  for (int i = 0; i < sourceRow.getLastCellNum(); i++) {
    Cell oldCell = sourceRow.getCell(i);
    Cell newCell = newRow.createCell(i);

    // コピー元の行が存在しない場合、処理を中断
    if (oldCell == null) {
      newCell = null;
      continue;
    }

    //スタイルのコピー
    CellStyle newCellStyle = workbook.createCellStyle();
    newCellStyle.cloneStyleFrom(oldCell.getCellStyle());
    newCell.setCellStyle(newCellStyle);

    //コメントのコピー
    if (oldCell.getCellComment() != null) {
      newCell.setCellComment(oldCell.getCellComment());
    }

    //ハイパーリンクのコピー
    if (oldCell.getHyperlink() != null) {
      newCell.setHyperlink(oldCell.getHyperlink());
    }

    //セル型のコピー
    newCell.setCellType(oldCell.getCellType());

    //セルの値をコピー
    switch (oldCell.getCellType()) {
    case Cell.CELL_TYPE_BLANK:
      newCell.setCellValue(oldCell.getStringCellValue());
      break;
    case Cell.CELL_TYPE_BOOLEAN:
      newCell.setCellValue(oldCell.getBooleanCellValue());
      break;
    case Cell.CELL_TYPE_ERROR:
      newCell.setCellErrorValue(oldCell.getErrorCellValue());
      break;
    case Cell.CELL_TYPE_FORMULA:
      newCell.setCellFormula(oldCell.getCellFormula());
      break;
    case Cell.CELL_TYPE_NUMERIC:
      newCell.setCellValue(oldCell.getNumericCellValue());
      break;
    case Cell.CELL_TYPE_STRING:
      newCell.setCellValue(oldCell.getRichStringCellValue());
      break;
    }
  }

  //セル結合のコピー
  for (int i = 0; i < worksheet.getNumMergedRegions(); i++) {
    CellRangeAddress cellRangeAddress = worksheet.getMergedRegion(i);
    if (cellRangeAddress.getFirstRow() == sourceRow.getRowNum()) {
      CellRangeAddress newCellRangeAddress = new CellRangeAddress(newRow.getRowNum(),
          (newRow.getRowNum() + (cellRangeAddress.getLastRow() - cellRangeAddress.getFirstRow())),
          cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastColumn());
      worksheet.addMergedRegion(newCellRangeAddress);
    }
  }
}

スポンサーリンク

コピーする内容

上のサンプルコードを見てもらえれば、分かると思いますが、今回紹介した行のコピーを行うサンプルコードでは、元の行から以下の内容をコピーする処理になっています。

コピーする内容
文字色・背景色などのセルスタイル
コメント
ハイパーリンク
セル型
セルの値
セル結合

スポンサーリンク

コピー先の行に、既に値がある場合

次の表のように、コピー先に既に行が存在する場合、今回紹介したサンプルコードでは、既に存在するコ行を1行ずらしてから、行のコピーを行っています。

[コピー前]

No 名称
1 りんご ← コピー元
2 みかん
3 もも ← コピー先

[コピー後]

No 名称
1 りんご
2 みかん
1 りんご
3 もも

ちなみに、この1行ずらす処理はサンプルコード17行目付近の、以下の部分で行っています。

    worksheet.shiftRows(destinationRowNum, worksheet.getLastRowNum(), 1);

まとめ

いかがでしょうか。
今回紹介したサンプルコードを、共通関数として保存しておけば、今後は共通関数を一発呼ぶだけになり、行のコピーが楽になるかと思います。

参考URL

みんな大好き stack overflow
https://stackoverflow.com/questions/5785724/how-to-insert-a-row-between-two-rows-in-an-existing-excel-with-hssf-apache-poi

※上記URLに掲載されているプログラムだと、うまく動かなかったので、本記事で紹介しているサンプルコードは一部修正しています。

スポンサーリンク
スポンサーリンク

このブログを検索

Profile

自分の写真
Webアプリエンジニア。 日々新しい技術を追い求めてブログでアウトプットしています。
プロフィール画像は、猫村ゆゆこ様に書いてもらいました。

仕事募集もしていたり、していなかったり。

QooQ