Apache POI Excel Sheet の全行 ⇒ 読込みObjecのリスト

Apache POI を使用した Excel の操作はずいぶん昔からコードを書いていた。
PushbackInputStream を使用する - Oboe吹きプログラマの黙示録
Excel 拡張子 (xls) (xlsx) 両方に対応した操作 Apache POI (2) - Oboe吹きプログラマの黙示録
Excel 拡張子 (xls) (xlsx) 両方に対応した操作 Apache POI(1) - Oboe吹きプログラマの黙示録
Apache POI でExcel 日付読込み(2) - Oboe吹きプログラマの黙示録
Apache POI でExcel 日付読込み - Oboe吹きプログラマの黙示録
Apache POI 入力規則リストの生成 - Oboe吹きプログラマの黙示録
Apache POI Excel 入力規則の読み込み(2) - Oboe吹きプログラマの黙示録
Apache POI Excel入力規則の読み込み(1) - Oboe吹きプログラマの黙示録

先日書いた ExcelWorker にさらにメソッドを追加する。

/**
 * Sheet ⇒ 読込みObject
 * @param <R>
 * @param sheetName シート名
 * @param func  Function<Sheet, R>
 * @return R
 */
public <R> R readSheetValue(String sheetName, Function<Sheet, R> func) {
    return Optional.ofNullable(book.getSheet(sheetName)).map(func::apply).orElse(null);
}
/**
 * Sheet の全行 ⇒ 読込みObjecのリスト
 * @param <R>
 * @param sheetName シート名
 * @param func Function<Row, R>
 * @return List<R>
 */
public <R> List<R> readRowList(String sheetName, Function<Row, R> func) {
    Sheet sheet = book.getSheet(sheetName);
    if (sheet==null) return new ArrayList<>();
    int last = sheet.getLastRowNum();
    return IntStream.range(0, last).boxed().map(i->func.apply(sheet.getRow(i))).collect(Collectors.toList());
}
/**
 * Sheet の全行 ⇒ 読込みObjecのリスト(行番号認識して)
 * @param <R>
 * @param sheetName シート名
 * @param func Function<Integer, Row, R>
 * @return List<R>
 */
public <R> List<R> readRowList(String sheetName, BiFunction<Integer, Row, R> func) {
    Sheet sheet = book.getSheet(sheetName);
    if (sheet==null) return new ArrayList<>();
    int last = sheet.getLastRowNum();
    return IntStream.range(0, last).boxed().map(i->func.apply(i, sheet.getRow(i))).collect(Collectors.toList());
}

Excel 拡張子 (xls) (xlsx) 両方に対応した操作 Apache POI (2) - Oboe吹きプログラマの黙示録
で書いていた、 Excelworker もいいかげん、まとめたものにしておきたい。

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.FileMagic;
import org.apache.poi.ss.SpreadsheetVersion;
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;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.util.IOUtils;
/**
 * ExcelWorker
 */
public class ExcelWorker implements Closeable{
    private Workbook book;

    private static final int MAX_PATTERN_LENGTH = 44;

    /**
    * コンストラクタ(File指定)
    * @param inst 読込み対象ExcelのInputStream
    * @throws IOException
    * @throws EncryptedDocumentException
    */
    public ExcelWorker(InputStream inst) throws EncryptedDocumentException, IOException {
       PushbackInputStream inp = new PushbackInputStream(inst, MAX_PATTERN_LENGTH);
       byte[] data = new byte[MAX_PATTERN_LENGTH];
       inp.read(data, 0, MAX_PATTERN_LENGTH);
       inp.unread(data);
       FileMagic fm = FileMagic.valueOf(data);
       if (FileMagic.OOXML==fm){
           book = new XSSFWorkbook(inp);
       }else if(FileMagic.OLE2==fm){
           book = new HSSFWorkbook(inp);
       }else {
           book = WorkbookFactory.create(inp);
       }
   }
    /**
    * コンストラクタ(File指定)
    * @param file 読込み対象ExcelのFile
    * @throws IOException
    * @throws EncryptedDocumentException
    */
   public ExcelWorker(File file) throws EncryptedDocumentException, IOException{
       FileMagic fm = valueFileMagic(file);
       if (fm==FileMagic.OOXML) {
           book = new XSSFWorkbook(new FileInputStream(file));
       }else if(fm==FileMagic.OLE2){
           book = new HSSFWorkbook(new FileInputStream(file));
       }else {
           book = WorkbookFactory.create(new FileInputStream(file));
       }
   }
   private FileMagic valueFileMagic(File file) throws IOException {
       try(FileInputStream fis = new FileInputStream(file)) {
           byte[] data = new byte[MAX_PATTERN_LENGTH];
           int read = IOUtils.readFully(fis, data, 0, MAX_PATTERN_LENGTH);
           if(read == -1) {
               return FileMagic.UNKNOWN;
           }
           data = Arrays.copyOf(data, read);
           return FileMagic.valueOf(data);
       }
   }

   /**
    * Excelバージョンを返す
    * @return SpreadsheetVersion,EXCEL2007 か。SpreadsheetVersion,EXCEL97 を返します
    */
    public SpreadsheetVersion getSpreadsheetVersion() {
        return book.getSpreadsheetVersion();
    }
    /**
     * Apche POI Workbook参照
     * @return
     */
    public Workbook getWorkbook() {
        return book;
    }
    /**
    * 先頭シート読み出し行(Row) Consumer を実行
    *
    * @param action Consumer<Row>
    */
    public void readFirstSheet(Consumer<Row> action) {
        Sheet sheet = book.getSheetAt(0);
        IntStream.rangeClosed(0, sheet.getLastRowNum()).mapToObj(n->sheet.getRow(n)).forEach(row->action.accept(row));
    }
    /**
    * 制限付き先頭シート読み出し行(Row) Consumer を実行
    *
    * @param pre 制限として指定する Predicate<Row>
    * @param action Consumer<Row>
    */
    public void readFirstSheet(Predicate<Row> pre, Consumer<Row> action) {
        Sheet sheet = book.getSheetAt(0);
        IntStream.rangeClosed(0, sheet.getLastRowNum()).mapToObj(n->sheet.getRow(n)).filter(pre).forEach(row->action.accept(row));
    }
   /**
    * 全ての Sheet Stream
    */
    public Stream<Sheet> getSheets(){
        return IntStream.range(0, book.getNumberOfSheets()).mapToObj(n->book.getSheetAt(n));
    }
   /**
    * 全てのSheet読み出しConsumerを実行
    * @param action Consumer<Sheet>
    */
    public void getSheets(Consumer<Sheet> action){
        IntStream.range(0, book.getNumberOfSheets()).mapToObj(n->book.getSheetAt(n)).forEach(action);
    }
    /**
     * Sheet ⇒ 読込みObject
     * @param <R>
     * @param sheetName シート名
     * @param func  Function<Sheet, R>
     * @return R
     */
    public <R> R readSheetValue(String sheetName, Function<Sheet, R> func) {
        return Optional.ofNullable(book.getSheet(sheetName)).map(func::apply).orElse(null);
    }
    /**
     * Sheet の全行 ⇒ 読込みObjecのリスト
     * @param <R>
     * @param sheetName シート名
     * @param func Function<Row, R>
     * @return List<R>
     */
    public <R> List<R> readRowList(String sheetName, Function<Row, R> func) {
        Sheet sheet = book.getSheet(sheetName);
        if (sheet==null) return new ArrayList<>();
        int last = sheet.getLastRowNum();
        return IntStream.range(0, last).boxed().map(i->func.apply(sheet.getRow(i))).collect(Collectors.toList());
    }
    /**
     * Sheet の全行 ⇒ 読込みObjecのリスト(行番号認識して)
     * @param <R>
     * @param sheetName シート名
     * @param func Function<Integer, Row, R>
     * @return List<R>
     */
    public <R> List<R> readRowList(String sheetName, BiFunction<Integer, Row, R> func) {
        Sheet sheet = book.getSheet(sheetName);
        if (sheet==null) return new ArrayList<>();
        int last = sheet.getLastRowNum();
        return IntStream.range(0, last).boxed().map(i->func.apply(i, sheet.getRow(i))).collect(Collectors.toList());
    }

    /**
    * 全てのSheet読み出しConsumerを実行
    * @param action Consumer<Sheet>
    */
    public static Stream<Row> getRowStream(Sheet sheet) {
        return IntStream.rangeClosed(0, sheet.getLastRowNum()).mapToObj(n->sheet.getRow(n));
    }
   /**
    * 行からセルのStreamを取得
    * @param row Row
    * @return Stream<Cell>
    */
    public static Stream<Cell> getCellStream(Row row){
        return IntStream.range(0, row.getLastCellNum()).mapToObj(n->row.getCell(n));
    }
   /**
    * シートデフォルト名で新規シート作成、先頭シートを size - 1 個クローンする。
    * @param book 作成対象Workbook
    * @param size 新規作成シート数
    * @return 作成したシートのStream
    */
    public static Stream<Sheet> createAndSheets(Workbook book, int size) {
        book.createSheet();
        for(int n=1; n < size;n++) {
            book.cloneSheet(0);
        }
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(book.sheetIterator(), Spliterator.ORDERED), false);
    }
    /**
    * シート名を指定した新規シート作成
    * @param book 作成対象Workbook
    * @param names 新規作成するシート名、可変長配列
    * @return 作成したシートのStream
    */
    public static Stream<Sheet> createAndSheets(Workbook book, String...names) {
        book.createSheet(names[0]);
        for(int n=1; n < names.length;n++) {
            book.createSheet(names[n]);
        }
        return StreamSupport.stream(Spliterators.spliteratorUnknownSize(book.sheetIterator(), Spliterator.ORDERED), false);
    }
    @Override
    public void close() throws IOException{
        book.close();
    }
}