9
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CellTypeを問わず、Cellの値を透過的に取得したい(Apache POI)

Posted at

Excel大好き日本企業にシステムを納めるJava大好きSIerとして働いている以上、避けては通れないのがApache POI。POIはExcelのセルを抽象化したCellというクラス(インタフェース)を持つのですが、このCellから値を取り出すのが意外と面倒。とりわけ__セルの表示形式(CellType)に合わせてメソッドを呼び分ける必要があり、かつCellTypeに合致しないメソッドを呼び出した場合は即座に例外を投げる__という仕様には何度苦しめられたことか(´・ω・`)

そこで__CellTypeを問わず、透過的にセルの値を取得できるユーティリティメソッド__を準備しておくことにしました。なお簡単な仕様としては以下の通りです。

  • POIがサポートするCellTypeのうちBLANK, BOOLEAN, NUMERIC, STRINGのみを対象とする。ただし日付についてもサポートする。
  • 戻り値はObject型とする。キャストするなりString#valueOfなり好きにすること。
  • サポートしないERRORFORMULAの場合は例外を送出する
    • 以下はサンプルのためRuntimeExceptionを投げているが、実際に利用する場合はちゃんとした例外(?)をスローすること。
  • null安全ではない。つまり引数がnullの場合はNullPointerExceptionを投げる。また万が一に備えてPOIがサポートしていないCellTypeのセルが引数と渡された場合も例外とする。
package my.excel;

import java.util.Objects;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.DateUtil;

final public class CellUtils {

    public static Object getCellValue(Cell cell) {
        Objects.requireNonNull(cell, "cell is null");
        
        CellType cellType = cell.getCellTypeEnum();
        if (cellType == CellType.BLANK) {
            return null;
        } else if (cellType == CellType.BOOLEAN) {
            return cell.getBooleanCellValue();
        } else if (cellType == CellType.ERROR) {
            throw new RuntimeException("Error cell is unsupported");
        } else if (cellType == CellType.FORMULA) {
            throw new RuntimeException("Formula cell is unsupported");
        } else if (cellType == CellType.NUMERIC) {
            if (DateUtil.isCellDateFormatted(cell)) {
                return cell.getDateCellValue();
            } else {
                return cell.getNumericCellValue();
            }
        } else if (cellType == CellType.STRING) {
            return cell.getStringCellValue();
        } else {
            throw new RuntimeException("Unknow type cell");
        }
    }
    
}

では実際に利用してみましょう(´・ω・`) まずは次のようなsample.xlsxを用意します。

sample.PNG

あとは次のようなコードを書いて、正しく読み込めるかどうかを確認してみます。

package my.excel;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class Main {
    public static void main(String ... args) {
        Path path = Paths.get("C:\\hogehoge\\sample.xlsx");
        try (Workbook workbook = WorkbookFactory.create(Files.newInputStream(path))) {
            Sheet sheet = workbook.getSheetAt(0);
            for (int i = 0; i <= sheet.getLastRowNum(); i++) {
                Row row = sheet.getRow(i);
                Cell cell = row.getCell(1); // B列のセルを取得する。
                Object value = CellUtils.getCellValue(cell);
                System.out.println(value);
            }
        } catch (IOException 
                    | InvalidFormatException 
                    | EncryptedDocumentException e) {
            e.printStackTrace();
        } 
    }
 }

コンパイルして実行した結果を確認してみると――確かに想定通り機能していることがわかります。やったね(´・ω・`)

ABC
true
100.0
Mon Jan 02 00:00:00 JST 2017
9
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?