| |
Apache POIを使う
Apache POI 5.3を使った際のメモです。
Java8以降が必須です。
なお、POIの仕様はバージョン3.6の後半から4になる間に大きく変わりましたが、
バージョン4と5の間では大きな変更はないみたいで、試した限りでは全く同じプログラムが動作しました。
インストール
POI4までは「poi-*-*-bin.zip」のようなバイナリ配布があったのですが、
公式ダウンロードページを見ると、
POI5ではpoiなにがしは生のjarを直接ダウンロードするようになっていて、
これにApache Commonsなど他のライブラリを追加でCLASSPATHを通して使う感じになっています。
私が試した所、(基本的な使い道には)以下のJARが必須となります。
poi-5.3.0.jar
poi-ooxml-5.3.0.jar
poi-ooxml-lite-5.3.0.jar
commons-collections4-4.4.ja
commons-compress-1.26.1.jar
commons-io-2.16.0.jar
commons-logging-1.1.jar
commons-math3-3.6.1.jar
log4j-api-2.23.1.jar
log4j-core-2.2.jar
log4j-jcl-2.2.jar
xmlbeans-5.2.1.jar
同じライブラリでも、バージョンが古いとエラーになるものがあります。
一例で、XMLBeansはver5以降が必須。Commons CompressとCommons IOも上記より少しでも古いバージョンだとエラーになります。
できるだけ新しい物を入れておくとよいでしょう。
新規Excelファイルを作る
まず最も簡単な、空のExcelブックに適当に文字を設定してファイルに出力するサンプルプログラムです。
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.xssf.usermodel.*;
public class OutputExample1 {
public static void main(String[] args) throws IOException {
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet s = wb.createSheet("新しいシート");
s.createRow(0);
XSSFRow row = s.createRow(1);
// 1〜2列目(0と1)をcreateCellしていなくても2列目から作成が可能
XSSFCell cell = row.createCell(2);
cell.setCellValue("こんにちは。");
cell = row.createCell(3);
cell.setCellValue(123.4);
FileOutputStream fos = new FileOutputStream("./output/output.xlsx");
wb.write(fos);
wb.close();
}
}
|
このように、シート名、セルに設定する文字列とも事前準備なしで日本語が使えます。
PHP系の他のライブラリと異なり、POIではブックを作っただけではシートは一つも自動では作られません。
1つ目のシートから自分で XSSFWorkbook#createSheet で作る必要があります。
また小さな注意点として、セルに値を設定するには先に createRow()とcreateCell()を使ってセルを作る必要がありますが、
createCell(2)で3列目のセルを作りたいとき、createCell(0)とcreateCell(1)は必須ではありません。
いきなり3列目のセルから作り始めてOKです。
セルの枠線、フォント、背景色
CellStyleというものでスタイルとして設定できます。
CellStyle style = wb.createCellStyle();
// 境界線の指定
style.setBorderTop(BorderStyle.THIN);
style.setTopBorderColor(IndexedColors.BLACK.index);
style.setBorderBottom(BorderStyle.THIN);
style.setBottomBorderColor(IndexedColors.BLACK.index);
style.setBorderLeft(BorderStyle.THIN);
style.setLeftBorderColor(IndexedColors.BLACK.index);
style.setBorderRight(BorderStyle.THIN);
style.setRightBorderColor(IndexedColors.BLACK.index);
// フォントの指定
Font font = wb.createFont();
font.setFontHeightInPoints((short) 10);
font.setFontName("Meiryo UI");
style.setFont(font);
// 塗りつぶし(25%灰色)と中央揃えを設定
style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.index);
style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER);
cell.setCellStyle(cs);
|
数値と日付の書式設定
cell.setCellValue(1234567.8);
CellStyle csnum = wb.createCellStyle();
csnum.cloneStyleFrom(cs);
csnum.setDataFormat(HSSFDataFormat.getBuiltinFormat("#,##0.00"));
cell.setCellStyle(csnum);
|
数値の整形例です。書式を「"[Red]#,##0.00"」と設定すると赤文字にもできます。
なお、書式が「"#,##0.00"」となっていますが、100万以上の値を設定した時も
「1,234,567,00」と二つ目以降のカンマも正しく設定されます。
次に日付の整形例です。POIではJavaのDateやCalendar型の値をセルに設定するだけでは、
Excelで開いたときの見た目が日付っぽくはなりません。
日付っぽい表示にするにはセル書式をそのように指定してやる必要があります。
cell.setCellValue(Calendar.getInstance());
CellStyle cscal = wb.createCellStyle();
cscal.cloneStyleFrom(cs);
cscal.setDataFormat((short)0xe);
cell.setCellStyle(cscal);
|
この例では日付書式を0xe、つまり10進数の14と設定しています。
これはExcelで「yyyy/m/d」の意味だとドキュメントではなっていますが多分「yyyy/mm/dd」、
つまり月と日は2桁左0詰される値になると思います。
自分で書式を設定することもできます。例えばyyyy-mm-ddがええんじゃいうんねやったら次のようにすると可能です。
cell.setCellValue(Calendar.getInstance());
CellStyle cscal = wb.createCellStyle();
cscal.cloneStyleFrom(cs);
cscal.setDataFormat(wb.createDataFormat().getFormat("yyyy-mm-dd"));
cell.setCellStyle(cscal);
|
列幅を指定する
特に問題ないと思います。
public static void setWidths(Sheet sheet, int[] widths){
for (short i = 0; i < widths.length; i++) {
if (widths[i] > 0 && widths[i] < 100) {
sheet.setColumnWidth(i, widths[i] * 256);
}
}
}
|
列幅の自動調整
Excelの機能を使って、各列の値が収まるように列幅を調整する指示も可能です。
シート内の列ごとに自動調整する・しないを選べます。
for(int x=0; x<7; x++) {
sheet.autoSizeColumn(x);
}
|
オートフィルターを付ける
引数はフィルターを付ける対象の開始行、終了行、開始列、終了列です。
sheet.setAutoFilter(new CellRangeAddress(0, 0, 0, 7));
|
Excelファイルから内容を読む
import java.io.IOException;
import org.apache.poi.xssf.usermodel.*;
public class InputExample1 {
private static XSSFCell getCell(XSSFSheet s, int rowno, int colno) {
XSSFRow row = s.getRow(rowno);
XSSFCell cell = row.getCell(colno);
return cell;
}
public static void main(String[] args) throws IOException {
XSSFWorkbook wb = new XSSFWorkbook("./input/order-sample.xlsx");
XSSFSheet s = wb.getSheetAt(0);
XSSFCell cell = getCell(s, 6, 1);
System.out.println(cell);
cell = getCell(s, 6, 3);
System.out.println(cell);
// ↑日付型の場合、デフォルト書式の「20-3月-2024」で出力される
cell = getCell(s, 6, 5);
System.out.println(cell);
cell = getCell(s, 6, 6);
System.out.println(cell);
// ↑式の場合、"E7*F7"のような式が出力される
wb.close();
}
}
|
今度は同様に、既存のExcelファイルから内容を読み込む簡単なサンプルです。
この例だと、コメントにあるように日付データは「20-3月-2024」のようなデフォルト書式になります。
また「=E7*F7」のような計算式のあるセルを読んだ場合、その式自体が得られ、計算結果の値は得られません。
これらを解決する方策は後述します。
読める日付と計算式の計算結果を読み取る
普段業務で使うExcelファイルに使っている値のタイプの多くは、数値、文字列、日付、計算式だと思います。
この内数値と文字列はそれぞれ Cell.getNumericCellValue()、Cell.getStringCellValue()
でJava世界で読める値になっているので問題ないのですが、問題は残りの二つです。
まず日付は、Excelの内部的には数値として持っているのでそのままだと数値が返ってしまいます。
日付としてJava世界に読み込むには次のようにします。
もう一つ、計算式の場合、Excelから読み込むと式そのものが返ってしまいます。
式の「計算結果」を取得したい場合どうするの?なんと、Java世界でExcelと同じ計算をするしかありません。
それをやってくれるのがFormulaEvaluatorというクラスで、使い方は以下の通りです。
private static final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
public static String getDisplayedCellValue(Cell cell){
String a = null;
switch (cell.getCellType()) {
case BOOLEAN:
a = String.valueOf(cell.getBooleanCellValue());
break;
case NUMERIC:
double d = cell.getNumericCellValue();
// NUMERICと判定された場合、さらに数値と日付の場合に分けられる。
// 日付書式ならば、日付として読める文字列に変換して返す。
if(DateUtil.isCellDateFormatted(cell)){
Date date = DateUtil.getJavaDate(d);
a = dateFormat.format(date);
} else {
a = String.valueOf(d);
}
break;
case STRING:
a = cell.getStringCellValue();
break;
case BLANK:
break;
case ERROR:
break;
case FORMULA:
// 計算式の値を評価して返す。
FormulaEvaluator ev =
cell.getSheet().getWorkbook().getCreationHelper().createFormulaEvaluator();
CellValue cv = ev.evaluate(cell);
a = getDisplayedCellValue(cv);
// 計算式の文字列(E7*F7など)を返すなら、下のようにする。
//a = cell.getCellFormula();
break;
default:
break;
}
return a;
}
public static String getDisplayedCellValue(CellValue cell){
String a = null;
if(cell != null){
switch (cell.getCellType()) {
case BOOLEAN:
a = String.valueOf(cell.getBooleanValue());
break;
case NUMERIC:
a = String.valueOf(cell.getNumberValue());
break;
case STRING:
a = cell.getStringValue();
break;
case BLANK:
break;
case ERROR:
break;
default:
break;
}
}
return a;
}
|

(first uploaded 2003/07/12 last updated 2024/08/18, URANO398)
|