共通インターフェースAPI
ソース1のプログラムはOOXML形式のファイルだけを扱うのであれば問題ありませんが、既存のOLE2形式のファイルも同時にサポート可能にしたい場合には対応できません。そこで、そのような要望に応えるためにPOI3.5から共通インターフェースを提供する「org.apache.poi.ss.usermodel」パッケージ(以降SSパッケージ)が導入されています。
SSパッケージにはXSSFとHSSFの共通のインターフェースが定義されており、SSパッケージのインターフェース群を利用することで、HSSFかXSSFを明示的に指定することなくUsermodel APIを利用できます。
前回紹介しましたサンプルプログラム「TimesheetDemoクラス」から一部抜粋したソースで確認してみましょう。
public static void main(String[] args) throws Exception { //(1)Workbookインターフェースの宣言 Workbook wb; //(2)Workbookインターフェースへの代入 if(args.length > 0 && args[0].equals("-xls")) wb = new HSSFWorkbook(); else wb = new XSSFWorkbook(); Map<String, CellStyle> styles = createStyles(wb); //(3)Sheetインターフェースへの代入 Sheet sheet = wb.createSheet("Timesheet"); PrintSetup printSetup = sheet.getPrintSetup(); printSetup.setLandscape(true); sheet.setFitToPage(true); sheet.setHorizontallyCenter(true); //(4)Rowインターフェースへの代入 Row titleRow = sheet.createRow(0); titleRow.setHeightInPoints(45); //(5)Cellインターフェースへの代入 Cell titleCell = titleRow.createCell(0); titleCell.setCellValue("Weekly Timesheet"); titleCell.setCellStyle(styles.get("title")); sheet.addMergedRegion(CellRangeAddress.valueOf("$A$1:$L$1"));
- ソース2 -(1)
- ソース2 -(2)
- ソース2 -(3)、(4)、(5)
SSパッケージが提供するWorkbookインターフェースを宣言しています。
引数の値に応じて、HSSFかXSSFのワークブックオブジェクトをWorkbookインターフェースに代入しています。どちらのワークブックオブジェクトが選択されても共通のWorkbookインターフェースに格納できることが確認できます。
いったんワークブックインターフェースにHSSFかXSSFのワークブックオブジェクトが代入された後は、「HSSF」や「XSSF」名がついたシート、行、セルオブジェクトはソース上には現れません。すべてインターフェースが代わりに利用されています。各インターフェースではUsermodel APIのメソッドが利用できています。なお、セルスタイルやフォント等の他のオブジェクトに関しても共通インターフェースがSSパッケージで提供されています。
WorkbookFactoryクラス
次に既存のExcelファイルを読み込んで利用するために用意されているAPIを確認しましょう。XSSFワークブックを読込む方法としては、次のコンストラクタが用意されています。
public XSSFWorkbook(java.io.InputStream is) throws java.io.IOException
一方、既存のHSSFワークブックを読み込む方法としては、次のコンストラクタが用意されていました。
public HSSFWorkbook(java.io.InputStream is) throws java.io.IOException
コンストラクタ内の処理をソースで確認してみると、XSSFでは「OPCPackage」が利用され、HSSFでは「POIFSFileSystem」が利用されているという違いがあるのですが、メソッドの呼出しだけの観点で言えば、「XSSFWorkbook」か「HSSFWorkbook」のいずれかのコンストラクタの名称を明確に指定するだけの違いです。
ただし、OOXMLとOLE2形式の両方のExcelファイルに対応するのであれば、SSパッケージで用意されている「WorkbookFactory」クラスを利用すると便利です。InputStreamオブジェクトを引数に渡すだけでXSSFWorkbookなのかHSSFWorkbookなのかを自動で判断して、適切なワークブックオブジェクトを生成後、Workbookインターフェースとして提供してくれます。サンプルプログラムで確認してみましょう。
import java.io.FileInputStream; import java.io.InputStream; 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 ReadWorkbook { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { //(1)入力ファイル名の取得 String fileName = args[0]; InputStream inp = new FileInputStream(fileName); //(2)入力ファイルを表すワークブックオブジェクトの生成 Workbook wb = WorkbookFactory.create(inp); // シート数分繰返す for (int i = 0; i < wb.getNumberOfSheets(); i++) { Sheet sheet = wb.getSheetAt(i); System.out.println(wb.getSheetName(i)); // 行数分繰返す for (Row row : sheet) { System.out.println("rownum: " + row.getRowNum()); for (Cell cell : row) { String cellValue = null; int cellType = cell.getCellType(); switch (cellType) { case Cell.CELL_TYPE_BOOLEAN: boolean bValue = cell.getBooleanCellValue(); cellValue = String.valueOf(bValue); break; case Cell.CELL_TYPE_NUMERIC: double dValue = cell.getNumericCellValue(); cellValue = String.valueOf(dValue); break; case Cell.CELL_TYPE_STRING: cellValue = cell.getStringCellValue(); break; case Cell.CELL_TYPE_BLANK: case Cell.CELL_TYPE_ERROR: case Cell.CELL_TYPE_FORMULA: default: continue; } // セル値の出力 System.out.println(cellValue); } } } } }
- ソース3 -(1)
- ソース3 -(2)
変数fileNameに引数を使って読込みたい入力ファイル名(「xlsx」または「xls」の拡張子付き)を代入します。
fileNameに代入したファイルの拡張子が「xlsx」であれば「XSSFWorkbook」が生成され、「xls」であれば「HSSFWorkbook」が自動で生成されます。戻り値はSSパッケージのWorkbookインターフェースです。
ソース上には「XSSF」や「HSSF」を明示的に指定する箇所や、コンポーネントの違いにより分岐処理をしている箇所はありません。
その後の処理は読込んだワークブックに含まれるワークシートごとに、各行を走査し、セルを表すオブジェクトを取得しています。そして、取得したセルの種類(論理型/数値型/文字列型)に応じて、セル値を取得し、文字列としてコンソールに出力しています。処理の途中でワークシート名や行番号も出力していますが、行番号は、書式設定の変更や値を設定したセルを含んでいる行だけが行番号が表示されます。それ以外の行オブジェクトはNullということになります。