Java Tips | I/O・ネットワーク:Excel読込

Java Java
スポンサーリンク
スポンサーリンク

Excel読込ユーティリティが業務で必須になる理由

Excelは業務データの“標準フォーマット”と言っても過言ではありません。 顧客リスト、売上データ、設定情報、外部ベンダーからの提供ファイル、社内の管理資料——どれも Excel(.xlsx)が使われます。 そのため、Java で Excel を読み込む処理は、ほぼすべての業務システムで必要になります。

しかし、初心者がやりがちな「Excel を CSV に変換して読み込む」「セルの型を意識せず文字列として読む」といった実装は、後から必ず破綻します。 Excel は「セルの型」「日付の扱い」「数値フォーマット」「空セル」「シート構造」など、独自のルールが多いため、正しく扱うにはユーティリティ化が不可欠です。

ここでは、初心者でも理解できるように噛み砕きながら、実務で通用する Excel 読込ユーティリティを丁寧に解説します。

Excel読込の基本発想

「ワークブック → シート → 行 → セル」という階層構造を理解する

Excel は階層構造でできています。

  • Workbook(ファイル)
  • Sheet(シート)
  • Row(行)
  • Cell(セル)

この階層を順番にたどることで、Excel の中身を読み取ることができます。

Java では Apache POI が事実上の標準ライブラリです。 POI を使うことで、Excel の構造をそのまま Java のオブジェクトとして扱えます。

Excel読込ユーティリティの基本形

Apache POI を使った最小構成の読み込み

まずは、最もシンプルな「Excel を読み込んで、行と列を文字列として取り出す」ユーティリティを見てみましょう。

import org.apache.poi.ss.usermodel.*;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

public class ExcelReader {

    public static List<List<String>> readSheet(Path path, int sheetIndex) throws Exception {
        try (InputStream in = Files.newInputStream(path);
             Workbook workbook = WorkbookFactory.create(in)) {

            Sheet sheet = workbook.getSheetAt(sheetIndex);
            List<List<String>> rows = new ArrayList<>();

            for (Row row : sheet) {
                List<String> cols = new ArrayList<>();
                for (Cell cell : row) {
                    cols.add(getCellValue(cell));
                }
                rows.add(cols);
            }
            return rows;
        }
    }

    private static String getCellValue(Cell cell) {
        if (cell == null) return "";

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();

            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getLocalDateTimeCellValue().toString();
                }
                return Double.toString(cell.getNumericCellValue());

            case BOOLEAN:
                return Boolean.toString(cell.getBooleanCellValue());

            case FORMULA:
                return cell.getCellFormula();

            case BLANK:
            default:
                return "";
        }
    }
}
Java

ここで深掘りしたいポイントは三つあります。

セルの型を必ず判定する

Excel のセルは「文字列」「数値」「日付」「真偽値」「式」など複数の型を持ちます。 型を無視して文字列として読むと、日付が数値になったり、式がそのまま文字列になったりします。

日付セルは DateUtil で判定する

Excel の日付は内部的には「数値」です。 そのため、DateUtil.isCellDateFormatted(cell) で判定し、日付として扱う必要があります。

空セルは null の可能性がある

Excel の行には「存在しないセル」があり得ます。 そのため、cell == null のチェックが必須です。

Excel読込ユーティリティのテンプレート

実務でそのまま使える形にまとめる

ここまでの内容をまとめて、より実務向けのテンプレートにします。

public class ExcelUtils {

    public static List<List<String>> read(Path path) throws Exception {
        return readSheet(path, 0); // デフォルトは1枚目
    }

    public static List<List<String>> readSheet(Path path, int sheetIndex) throws Exception {
        try (InputStream in = Files.newInputStream(path);
             Workbook workbook = WorkbookFactory.create(in)) {

            Sheet sheet = workbook.getSheetAt(sheetIndex);
            List<List<String>> rows = new ArrayList<>();

            int lastRow = sheet.getLastRowNum();

            for (int r = 0; r <= lastRow; r++) {
                Row row = sheet.getRow(r);
                List<String> cols = new ArrayList<>();

                if (row != null) {
                    int lastCol = row.getLastCellNum();
                    for (int c = 0; c < lastCol; c++) {
                        Cell cell = row.getCell(c);
                        cols.add(getCellValue(cell));
                    }
                }
                rows.add(cols);
            }
            return rows;
        }
    }

    private static String getCellValue(Cell cell) {
        if (cell == null) return "";

        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue();

            case NUMERIC:
                if (DateUtil.isCellDateFormatted(cell)) {
                    return cell.getLocalDateTimeCellValue().toString();
                }
                return Double.toString(cell.getNumericCellValue());

            case BOOLEAN:
                return Boolean.toString(cell.getBooleanCellValue());

            case FORMULA:
                return cell.getCellFormula();

            case BLANK:
            default:
                return "";
        }
    }
}
Java

Excel読込で絶対に意識してほしい重要ポイント

1. Excel の日付は「数値」である

Excel の日付は内部的には「1900年1月1日からの経過日数」です。 そのため、日付セルを文字列として読むと「45000.0」のような数値になります。

必ず DateUtil.isCellDateFormatted(cell) を使って判定してください。

2. 空セルは「存在しない」場合がある

Excel の行は「セルが存在しない」ことがあります。 そのため、row.getCell(c) が null を返すことがあります。

必ず null チェックを入れてください。

3. シートの行数・列数は「飛び飛び」になる

Excel は「途中の行が空」「途中の列が空」という構造が普通にあります。 そのため、getLastRowNum()getLastCellNum() を使って範囲を決める必要があります。

4. 文字コードは気にしなくてよい(Excelはバイナリ形式)

CSV と違い、Excel はバイナリ形式なので文字コードを意識する必要はありません。 ただし、Excel 内の文字列は UTF-16 で保持されるため、POI が自動的に変換してくれます。

Excel読込ユーティリティの実務的な使いどころ

外部ベンダーからの Excel インポート

顧客データ、売上データ、商品マスタなど、Excel で提供されることが非常に多いです。 ユーティリティ化しておくことで、どの画面でも同じルールで読み込めます。

管理画面からの Excel アップロード

「Excel をアップロードして一括登録」という機能は定番です。 ユーティリティを使うことで、セル型・日付・空セルなどの扱いが統一されます。

バッチ処理での Excel 読込

夜間バッチで Excel を読み込む場合、 ユーティリティ化しておくことで、例外処理やログ出力が安定します。

まとめ:Excel読込ユーティリティで身につけてほしい感覚

Excel読込ユーティリティは、業務データを正しく取り込むための“入り口”です。 そこには次のような大事なポイントがあります。

  • Excel は「ワークブック → シート → 行 → セル」の階層構造で読む
  • セル型(文字列・数値・日付・式)を必ず判定する
  • 日付セルは内部的に数値なので、DateUtil で判定する
  • 空セルは null の可能性があるため、必ずチェックする
  • 行数・列数は飛び飛びになるため、範囲を明示する
  • ユーティリティ化することで、画面・バッチ・連携処理の品質が統一される

タイトルとURLをコピーしました