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.InputStreamReader; import java.io.Reader; import java.io.Writer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; import java.util.Map; import org.apache.commons.io.input.BOMInputStream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.dataformat.csv.CsvGenerator; import com.fasterxml.jackson.dataformat.csv.CsvMapper; import com.fasterxml.jackson.dataformat.csv.CsvSchema; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import hrytsenko.gscripts.AppException; import hrytsenko.gscripts.util.NamedArgs; import hrytsenko.gscripts.util.Records; /** * Extensions for load and save of the CSV files. * * <p> * Named arguments: * <dl> * <dt>{@link NamedArgs#PATH}</dt> * <dd>The path to file.</dd> * <dt>{@link #CHARSET}</dt> * <dd>The character set for file, default: UTF-8 ({@link #CHARSET_DEFAULT}).</dd> * <dt>{@link #SEPARATOR}</dt> * <dd>The separator of columns, default: comma ({@link #SEPARATOR_DEFAULT}).</dd> * <dt>{@link #QUALIFIER}</dt> * <dd>The qualifier for text, default: double-quote ({@link #QUALIFIER_DEFAULT}).</dd> * </dl> * * @author hrytsenko.anton */ public final class CsvFiles { private static final Logger LOGGER = LoggerFactory.getLogger(CsvFiles.class); public static final String CHARSET = "charset"; public static final Charset CHARSET_DEFAULT = StandardCharsets.UTF_8; public static final String QUALIFIER = "qualifier"; public static final String QUALIFIER_DEFAULT = "\""; public static final String SEPARATOR = "separator"; public static final String SEPARATOR_DEFAULT = ","; private CsvFiles() { } /** * Load records from file. * * @param args * the named arguments. * * @return the list of text records. * * @throws AppException * if file could not be loaded. */ public static List<Map<String, String>> loadCsv(Map<String, ?> args) { Path path = NamedArgs.findPath(args); LOGGER.info("Load {}.", path.getFileName()); CsvSchema schema = schemaFrom(args).setUseHeader(true).build(); try (InputStream dataStream = Files.newInputStream(path); InputStream bomStream = new BOMInputStream(dataStream); Reader dataReader = new InputStreamReader(bomStream, charsetFrom(args))) { CsvMapper mapper = new CsvMapper(); ObjectReader reader = mapper.readerFor(Map.class).with(schema); return Lists.newArrayList(reader.readValues(dataReader)); } catch (Exception exception) { throw new AppException(String.format("Could not load file %s.", path.getFileName()), exception); } } /** * Save records into file. * * <p> * If file already exists, then it will be overridden. * * @param records * the list of records to save. * @param args * the named arguments. * * @throws IOException * if file could not be saved. */ public static void saveCsv(List<Map<String, ?>> records, Map<String, ?> args) { if (records.isEmpty()) { LOGGER.info("No records to save."); return; } Path path = NamedArgs.findPath(args); LOGGER.info("Save {}.", path.getFileName()); CsvSchema.Builder csvSchema = schemaFrom(args).setUseHeader(true); Records.columns(records).forEach(csvSchema::addColumn); try (Writer writer = Files.newBufferedWriter(path, charsetFrom(args))) { CsvMapper csvMapper = new CsvMapper(); csvMapper.configure(CsvGenerator.Feature.ALWAYS_QUOTE_STRINGS, true); csvMapper.writer().with(csvSchema.build()).writeValue(writer, Records.normalize(records)); } catch (IOException exception) { throw new AppException(String.format("Could not save file %s.", path.getFileName()), exception); } } private static Charset charsetFrom(Map<String, ?> args) { return NamedArgs.tryFind(args, CHARSET).map(Charset::forName).orElse(CHARSET_DEFAULT); } private static CsvSchema.Builder schemaFrom(Map<String, ?> args) { String separator = NamedArgs.tryFind(args, SEPARATOR).orElse(SEPARATOR_DEFAULT); Preconditions.checkArgument(separator.length() == 1, "Invalid separator."); String qualifier = NamedArgs.tryFind(args, QUALIFIER).orElse(QUALIFIER_DEFAULT); Preconditions.checkArgument(qualifier.length() == 1, "Invalid qualifier."); return CsvSchema.builder().setColumnSeparator(separator.charAt(0)).setQuoteChar(qualifier.charAt(0)); } }