Apache POIの覚え書き Excel読み取り編

# はじめに
この投稿は個人的なメモ書きです。
Apache-POIを利用してExcelファイルを読み取る時に、メソッドの使い方や気をつけることなどのtipsをまとめていこうと思います。
内容は随時更新していく予定です。

# 準備
POIのバージョンは投稿時の最新Release版の3.14を使っています。

今回はMavenを使うのでpom.xmlに下記を追加

```xml
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi</artifactId>
  <version>3.14</version>
</dependency>
```
さらにxlsxファイルを扱いたいので下記も追加

```xml
<dependency>
  <groupId>org.apache.poi</groupId>
  <artifactId>poi-ooxml</artifactId>
  <version>3.14</version>
</dependency>
```
ファイルを開くときに使用する```org.apache.poi.ss.usermodel.WorkbookFactory```などは
ooxmlの方に含まれているので、両方入れておくのをオススメします。


# Excelファイルの読み取り
## ファイル
```java
// java.io.Fileから
Workbook workbook = WorkbookFactory.create(new File("ファイルパス"));

// java.io.inputStream
InputStream inputStream = new FileInputStream("ファイルパス");
Workbook workbook = WorkbookFactory.create(inputStream);
```

## シート
```java
// シート名がわかっている場合
Sheet sheet = workbook.getSheet("シート名");

// 取得したいシートが何番目かわかっている場合
// シート番号はゼロベース
Sheet sheet = workbook.getSheetAt(0);

// 全シートを繰り返し処理する場合
Iterator<Sheet> sheets = workbook.sheetIterator();
while(sheets.hasNext()) {
  Sheet sheet = sheets.next();
}
```

## 行（Row）
```java
// 取得したい行数がわかっている場合
// 行番号はゼロベース
Row row = sheet.getRow(0);

// 全行を繰り返し処理する場合
Iterator<Row> rows = sheets.rowIterator();
while(rows.hasNext()) {
  Row row = rows.next();
}
```

## セル（Cell）
```java
// 取得したいセルの位置がわかっている場合
// セル番号はゼロベース
Cell cell = row.getCell(0);

// 全セルを繰り返し処理する場合
Iterator<Cell> cells = row.cellIterator();
while(cells.hasNext()) {
  Cell cell = cells.next();
}
```

### セルの書式（数値、文字、関数など）の判定
```java
switch(cell.getCellType()) {
  // 数値
　// 日付も数値として判定される
  case Cell.CELL_TYPE_NUMERIC:
      ...
    break;
　// 関数（SUMとかIFとか）
  case Cell.CELL_TYPE_FORMULA:
      ...
    break;
  // 真偽
  case Cell.CELL_TYPE_BOOLEAN:
      ...
    break;
  // 文字列
  case Cell.CELL_TYPE_STRING:
      ...
    break;
  // 空
  case Cell.CELL_TYPE_BLANK:
      ...
    break;
  default:
    break;
}
```


### 値の取得
Cell#getValue()のような単純なものであればいいのですが、
前述のセルの種類にあわせて、それぞれ別のメソッドで呼び分ける必要があります。

```java
// 文字列の取得
// 数値の入ったセルに対して実行すると怒られる
String stringValue = cell.getStringCellValue();

// 関数の取得
// 関数の文字列がそのまま取得できる　例：SUM(A1,B2)
String formula = cell.getCellFormula();

// 数値の取得
// もちろん文字列のセルでは怒られる
Double numericValue = cell.getNumericCellValue();

// 日付の取得
// Excel標準の日付書式を使っている場合
if(org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
  java.util.Date date = cell.getDateCellValue();

  // java.time.DateTimeFormatterで文字列化
  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss.SSS");
  LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
  String formatted = dateTimeFormatter.format(localDateTime);
}

// ユーザー定義型で日付を設定している場合
if(BuiltinFormats.FIRST_USER_DEFINED_FORMAT_INDEX <= cell.getCellStyle().getDataFormat()) {
  CellFormat cellFormat = CellFormat.getInstance(
      cell.getCellStyle().getDataFormatString()
  );
  CellFormatResult cellFormatResult = cellFormat.apply(cell);
  String formatted = cellFormatResult.text;
}
```

### 書式設定の取得
```java
// 罫線の取得
// 下記いずれかの値が取得できる。v3.15ではBorderStyleに変わる？
// CellStyle.BORDER_THIN
// CellStyle.BORDER_THICK
// CellStyle.BORDER_DOUBLE
// CellStyle.BORDER_HAIR
// CellStyle.BORDER_DASH_DOT
// CellStyle.BORDER_DASH_DOT_DOT
// CellStyle.BORDER_DASHED
// CellStyle.BORDER_DOTTED
// CellStyle.BORDER_MEDIUM_DASH_DOT
// CellStyle.BORDER_MEDIUM_DASH_DOT_DOT
// CellStyle.BORDER_MEDIUM_DASHED
// CellStyle.BORDER_SLANTED_DASH_DOT
CellStyle cellStyle = cell.getCellStyle();
short borderTop    = cellStyle.getBorderTop();
short borderBottom = cellStyle.getBorderBottom();
short borderLeft   = cellStyle.getBorderLeft();
short borderLeft   = cellStyle.getBorderRight();

// 背景色の取得
// xlsxファイルの場合
Color bgColor = cellStyle.getFillForegroundColorColor();
if(bgColor instanceof XSSFColor) {
  // RGB16進数表記へ変換
  byte[] bytes = ((XSSFColor) bgColor).getRGB();
  StringBuilder builder = new StringBuilder();
  for(byte b : bytes) {
    builder.append(String.format("%02x", b));
  }
  String hexRgbCode = builder.toString();
}

// 文字色の取得
// xlsxファイルの場合
Font font = cell.getSheet().getWorkbook().getFontAt(cellStyle.getFontIndex());
if(font instanceof XSSFFont) {
  // 太字か？
  XSSFFont xssfFont = (XSSFFont) font;
  boolean isBoldStyle = xssfFont.getBold();

  XSSFColor fontColor = xssfFont.getXSSFColor();
  if(fontColor != null) {
    // RGB16進数表記へ変換
    byte[] bytes = fontColor.getRGB();
    StringBuilder builder = new StringBuilder();
    for(byte b : bytes) {
      builder.append(String.format("%02x", b));
    }
    String hexRgbCode = builder.toString();
  }
}
```

- その他
 - ほかにもたくさんあります
 - そのうち...追記する...かも...

# おわりに
POIを利用したExcelファイルの読み取りについてまとめました。
個人の願いとしては、JavaでExcelファイルを読み書きしなくていい時代が
来て欲しいと思っています。