Apache POIでExcelファイルを扱う

# 概要
業務でJavaプログラムからExcelファイルを参照、出力（作成）する必要があり、その際に Apache POI を用いて対応したので、その基本的な操作をまとめた。

## Apache POI とは？
Apacheプロジェクトの1つで、Word や Excel などの Microsoft Office 形式のファイルを読み書きできる 100% Java ライブラリ。  
_※ POI という名称は、Office のファイル形式をリバースエンジニアリングした際、その形式が意図的、中途半端に分かりにくくされていたため、皮肉を込め "Poor Obfuscation Implementation"（質の悪い難読な実装）と呼んだものの頭字語に由来している。_

# Apache POI の入手
[Apache POI の公式サイト](https://poi.apache.org/download.html)より、ライブラリを取得する。
（2020年3月時点の最新バージョンは 4.1.2 だが、今回は業務対応時点での最新だった、3.17 にて実装）

# サンプルコード
既存のExcelファイルから値を取得し、内容を追記して別のExcelファイルに出力するサンプル。
### コード

```Java:ApachePoiSample.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

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 ApachePoiSample {

	/** 入力Excelファイルパス */
	public static final String IN_EXCEL_FILE_PATH = "excel/in/sample.xlsx";
	/** 出力Excelファイルパス */
	public static final String OUT_EXCEL_FILE_PATH = "excel/out/output.xlsx";

	public static void main(String[] args) {

		//---- Excelファイルを開く ----
		Workbook wb = null;
		try ( InputStream is = new FileInputStream(IN_EXCEL_FILE_PATH); ) {
			wb = WorkbookFactory.create(is);
		} catch (FileNotFoundException e) {
			// 対象のExcelファイルが存在しない場合に発生
		    e.printStackTrace();
		} catch (IOException e) {
			// 対象のExcelファイルの読み込みに失敗した場合に発生
		    e.printStackTrace();
		} catch (EncryptedDocumentException e) {
			// 対象のExcelファイルにパスワードが設定されている場合に発生
			e.printStackTrace();
		} catch (InvalidFormatException e) {
			// 対象のExcelファイルが無効な形式である場合に発生
			e.printStackTrace();
		}

		// 対象のシートを選択する
		Sheet sheet1 = wb.getSheet("Sheet1");

		//---- A列の各セルから値を取得する ----
		System.out.println("＜入力＞");

		// 文字列を取得する
		Row row = sheet1.getRow(0);		// 1行目
		Cell cell = row.getCell(0);		// A列
		String a1 = cell.getStringCellValue();
		System.out.println("A1 : " + a1);

		// 数値を取得する
		row = sheet1.getRow(1);			// 2行目
		cell = row.getCell(0);			// A列
		double a2 = cell.getNumericCellValue();
		System.out.println("A2 : " + a2);

		// 数式を取得する
		row = sheet1.getRow(2);			// 3行目
		cell = row.getCell(0);			// A列
		String a3 = cell.getCellFormula();
		System.out.println("A3 : " + a3);

		//---- 出力用にB列に値を追記する（B列は空のため、新規にセルを作成する）----
		System.out.println("＜出力＞");

		// 文字列を出力する
		row = sheet1.getRow(0);			// 1行目
		cell = row.createCell(1);		// B列の作成
		cell.setCellValue(a1 + a1);
		System.out.println("B1 : " + cell.getStringCellValue());

		// 数値を出力する
		row = sheet1.getRow(1);			// 2行目
		cell = row.createCell(1);		// B列の作成
		cell.setCellValue(a2 + a2);
		System.out.println("B2 : " + cell.getNumericCellValue());

		// 数式を出力する
		row = sheet1.getRow(2);			// 3行目
		cell = row.createCell(1);		// B列の作成
		cell.setCellFormula("B2*2");
		System.out.println("A3 : " + cell.getCellFormula());

		//---- Excelファイルに出力する ----
		try ( FileOutputStream os = new FileOutputStream(OUT_EXCEL_FILE_PATH); ) {
			wb.write(os);
		} catch (FileNotFoundException e) {
			// 出力先に指定されたパスが存在しない場合に発生
			e.printStackTrace();
		} catch (IOException e) {
			// Excelファイルの出力に失敗した場合に発生
			e.printStackTrace();
		}
	}

}
```

### 実行結果
##### 入力ファイル（sample.xlsx）
A1セルに文字列（Sample）、A2セルに数値（1.23）、A3セルに数式（A2*2）が入力されている。
![sample.xlsx](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339580/01246080-19cd-085e-340f-0d4f2254fe04.png)

##### コンソールログ
入力ファイルのA列の各値が取得されている。
また、出力ファイル用の値を以下の様に設定。

```
＜入力＞
A1 : sample
A2 : 1.23
A3 : A2*2
＜出力＞
B1 : samplesample
B2 : 2.46
A3 : B2*2
```

##### 出力ファイル（output.xlsx）
プログラム中で設定した各値がB列に出力されている。
![output.xlsx](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/339580/a23cc2fd-f62e-4278-aa25-70c84de35589.png)