Java tutorial
/* * #%L * gscripts * %% * Copyright (C) 2015 Anton Hrytsenko * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ package hrytsenko.gscripts.io; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.text.DecimalFormat; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Spliterator; import java.util.Spliterators; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableList; import hrytsenko.gscripts.AppException; import hrytsenko.gscripts.util.NamedArgs; import hrytsenko.gscripts.util.Records; /** * Methods for load/save of XLSX files. * * <p> * Named arguments: * <dl> * <dt>{@link NamedArgs#PATH}</dt> * <dd>The path to file.</dd> * <dt>{@link #SHEET_NAME}</dt> * <dd>The name of sheet, default: {@link #SHEET_NAME_DEFAULT}.</dd> * </dl> * * @author hrytsenko.anton */ public final class XlsFiles { private static final Logger LOGGER = LoggerFactory.getLogger(XlsFiles.class); private static final String SHEET_NAME = "sheetName"; private static final String SHEET_NAME_DEFAULT = "records"; private XlsFiles() { } /** * Loads record from file. * * @param args * the named arguments. * * @return the list of records. * * @throws IOException * if file could not be loaded. */ public static List<Map<String, String>> loadXls(Map<String, ?> args) { Path path = NamedArgs.findPath(args); LOGGER.info("Load {}.", path.getFileName()); try (InputStream stream = Files.newInputStream(path); Workbook workbook = WorkbookFactory.create(stream);) { Sheet sheet = workbook.getSheetAt(0); List<Row> rows = ImmutableList.copyOf(sheet.rowIterator()); if (rows.isEmpty()) { return Collections.emptyList(); } List<String> columns = rows.stream().findFirst().map(XlsFiles::cellValues) .orElseThrow(() -> new IllegalStateException("Cannot read columns.")); return rows.stream().skip(1).map(toRecord(columns)).collect(Collectors.toList()); } catch (Exception exception) { throw new AppException(String.format("Could not load file %s.", path.getFileName()), exception); } } private static Function<Row, Map<String, String>> toRecord(List<String> columns) { return row -> IntStream.range(0, columns.size()) .collect(LinkedHashMap::new, (r, i) -> r.put(columns.get(i), Optional.ofNullable(row.getCell(i)).map(XlsFiles::cellValue).orElse("")), Map::putAll); } /** * Save records to file. * * <p> * If file already exists, then it will be overridden. * * @param input * the list of records to save. * @param args * the named arguments {@link XlsFiles}. * * @throws IOException * if file could not be saved. */ public static void saveXls(List<Map<String, ?>> input, Map<String, ?> args) { if (input.isEmpty()) { LOGGER.info("No records to save."); return; } Path path = NamedArgs.findPath(args); LOGGER.info("Save {}.", path.getFileName()); try (OutputStream stream = Files.newOutputStream(path); Workbook workbook = new XSSFWorkbook()) { Sheet sheet = workbook.createSheet(); workbook.setSheetName(0, NamedArgs.tryFind(args, SHEET_NAME).orElse(SHEET_NAME_DEFAULT)); List<String> columns = Records.columns(input); int columnsNum = columns.size(); Row header = createHeader(sheet); createCells(header, columnsNum).forEach(setValueByPos(columns::get)); int recordsNum = input.size(); createRows(sheet, recordsNum).forEach(row -> { Map<String, String> record = Records.normalize(input.get(row.getRowNum() - 1)); createCells(row, columnsNum).forEach(setValueByPos(i -> record.get(columns.get(i)))); }); workbook.write(stream); } catch (IOException exception) { throw new AppException(String.format("Could not save file %s.", path.getFileName()), exception); } } private static Row createHeader(Sheet sheet) { sheet.createFreezePane(0, 1); return sheet.createRow(0); } private static Stream<Row> createRows(Sheet sheet, int total) { return IntStream.range(0, total).map(i -> i + 1).mapToObj(sheet::createRow); } private static Stream<Cell> createCells(Row row, int total) { return IntStream.range(0, total).mapToObj(row::createCell); } private static Consumer<Cell> setValueByPos(Function<Integer, String> supplier) { return cell -> cell.setCellValue(supplier.apply(cell.getColumnIndex())); } private static List<String> cellValues(Row row) { return StreamSupport .stream(Spliterators.spliteratorUnknownSize(row.cellIterator(), Spliterator.ORDERED), false) .map(XlsFiles::cellValue).collect(Collectors.toList()); } private static String cellValue(Cell cell) { switch (cell.getCellType()) { case Cell.CELL_TYPE_STRING: return cell.getStringCellValue(); case Cell.CELL_TYPE_NUMERIC: DecimalFormat format = new DecimalFormat("0.#"); return format.format(cell.getNumericCellValue()); case Cell.CELL_TYPE_BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); default: return ""; } } }