All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.api.ads.common.lib.utils.CsvFiles Maven / Gradle / Ivy

Go to download

Client library for Java for accessing ads APIs including DFP. If you want to use this library, you must also include another Maven artifact to specify which framework you would like to use it with. For example, to use DFP with Axis, you should include the "dfp-axis" artifact.

There is a newer version: 5.6.0
Show newest version
// Copyright 2010 Google Inc. All Rights Reserved.
//
// 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.

package com.google.api.ads.common.lib.utils;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.io.Files;
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * A utility class for processing and handling CSV files.
 */
public final class CsvFiles {
  /**
   * {@code CsvFiles} is meant to be used statically.
   */
  private CsvFiles() {}

  /**
   * Returns a {@code Map} mapping of the column designated by
   * {@code key} to the column designated by {@code value}. This method also
   * ignores all columns other than the columns specified by {@code key} and
   * {@code value}.
   *
   * @param fileName the CSV file to load
   * @param key the 0-indexed column number to map to the key of the returned
   *     data map
   * @param value the column number to map to the value of the returned data
   *     map
   * @param headerPresent {@code true} if the fist line is the header
   * @return a {@code Map} mapping of the columns specified by
   *     {@code key} and {@code value}
   * @throws IOException if there was an error while reading the file
   * @throws IllegalArgumentException if CSV file does not have the
   *     columns specified by {@code key} or {@code value}
   */
  public static Map getCsvDataMap(String fileName,
      final int key, final int value, boolean headerPresent) throws IOException {    
    final Map result = Maps.newHashMap();
    new CsvReader(fileName, headerPresent)
        .processReader((header, line, lineNumber) -> result.put(line[key], line[value]));
    return result;
  }

  /**
   * Returns a {@code Map} mapping of the first column to the
   * second column. This method also ignores all columns other than the first
   * two.
   *
   * @param fileName the CSV file to load
   * @param headerPresent {@code true} if the fist line is the header
   * @return a {@code Map} mapping of the first to the second
   *     column
   * @throws IOException if there was an exception reading the file
   * @throws IllegalArgumentException if CSV file has fewer than two
   *     columns
   */
  public static Map getCsvDataMap(String fileName, boolean headerPresent)
      throws IOException {
    return getCsvDataMap(fileName, 0, 1, headerPresent);
  }

  /**
   * Returns a {@code Map} mapping of the first column to an
   * array of the rest of the columns.
   *
   * @param fileName the CSV file to load
   * @param headerPresent {@code true} if the fist line is the header
   * @return a {@code Map} mapping of the first column to an
   *     array of the rest of the columns
   * @throws IllegalArgumentException if there is fewer than 2 columns in
   *     the CSV
   * @throws IOException if there was an exception reading the file
   */
  public static Map getCsvDataMapArray(String fileName, boolean headerPresent)
      throws IOException {
    final Map result = Maps.newHashMap();
    new CsvReader(fileName, headerPresent)
        .processReader(
            (header, line, lineNumber) ->
                result.put(
                    line[0],
                    Arrays.asList(line)
                        .subList(1, line.length)
                        .toArray(new String[line.length - 1])));
    return result;
  }

  /**
   * Returns a {@code List>} that contains all rows with
   * a field mapping defined by the header. If no header is present,
   * then each field is the 0-indexed column number.
   *
   * @param fileName the CSV file to load
   * @param headerPresent {@code true} if the first line is the header
   * @return a {@code List>} that contains all rows with
   *     with a field mapping defined by the header if present.
   * @throws IOException if there was an exception reading the file
   */
  public static List> getCsvDataListMap(String fileName,
      boolean headerPresent) throws IOException {
    final List> result = Lists.newArrayList();
    new CsvReader(fileName, headerPresent)
        .processReader(
            (headers, line, lineNumber) -> {
              Map data = Maps.newHashMap();
              for (int i = 0; i < line.length; i++) {
                if (headers != null) {
                  data.put(headers[i], line[i]);
                } else {
                  data.put(i + "", line[i]);
                }
              }
              result.add(data);
            });
    return result;
  }

  /**
   * Returns a {@code List} representing a single 0-indexed column.
   *
   * @param fileName the CSV file to load
   * @param column the 0-indexed column to return
   * @param headerPresent {@code true} if the first line is the header
   * @return a {@code List} representing a single column
   * @throws IOException if there was an exception reading the file
   * @throws IllegalArgumentException if the column index does not exist in
   *     the CSV
   */
  public static List getCsvDataByColumn(String fileName, final int column,
      boolean headerPresent) throws IOException {
    final List result = Lists.newArrayList();
    new CsvReader(fileName, headerPresent)
        .processReader((headers, line, lineNumber) -> result.add(line[column]));
    return result;
  }


  /**
   * Returns a {@code List} that contains all rows of the CSV file.
   * The header will be removed, if present.
   *
   * @param fileName the CSV file to load
   * @param headerPresent {@code true} if the first line is the header
   * @return a {@code List} that contains all rows of the CSV file
   * @throws IOException if there was an exception reading the file
   */
  public static List getCsvDataArray(String fileName, boolean headerPresent)
      throws IOException {
    final List result = Lists.newArrayList();
    new CsvReader(fileName, headerPresent)
        .processReader((headers, line, lineNumber) -> result.add(line));
    return result;
  }

  /**
   * Returns a {@code List} that contains all rows of the CSV file.
   * The header will be removed, if present.
   *
   * @param csvReader reader used to read the csv
   * @param headerPresent {@code true} if the first line is the header
   * @return a {@code List} that contains all rows of the CSV file
   * @throws IOException if there was an exception reading the file
   */
  public static List getCsvDataArray(Reader csvReader, boolean headerPresent)
      throws IOException {
    final List result = Lists.newArrayList();
    new CsvReader(new CSVReader(csvReader), headerPresent)
        .processReader((headers, line, lineNumber) -> result.add(line));
    return result;
  }
  /**
   * Writes the CSV data located in {@code csvData} to the file located at
   * {@code fileName}.
   *
   * @param csvData the CSV data including the header
   * @param fileName the file to write the CSV data to
   * @throws IOException if there was an error writing to the file
   * @throws NullPointerException if {@code csvData == null} or {@code fileName == null}
   */
  public static void writeCsv(List csvData, String fileName) throws IOException {
    Preconditions.checkNotNull(csvData, "Null CSV data");
    Preconditions.checkNotNull(fileName, "Null file name");

    CSVWriter writer = null;
    try {
      writer = new CSVWriter(Files.newWriter(new File(fileName), StandardCharsets.UTF_8));
      for (String[] line : csvData) {
        writer.writeNext(line);
      }
    } finally {
      if (writer != null) {
        writer.close();
      }
    }
  }

  /**
   * Iterates through and processes each line of a CSV file. This is done by
   * passing a {@link CsvWorker} object into the
   * {@link CsvReader#processReader(CsvWorker)} method, which in turn, calls the
   * {@link CsvWorker#processLine(String[], String[], int)} method for each line
   * of the CSV.
   */
  private static class CsvReader {
    private final String fileName;
    private final boolean headerPresent;
    private CSVReader reader;
    private String[] header;
    private int lineNumber;

    /**
     * Constructs a {@link CsvReader} object which will load the file located
     * at {@code fileName}.
     *
     * @param fileName the file name of the CSV file to load
     * @param headerPresent {@code true} if the file's first line is the
     *     header for each column
     */
    public CsvReader(String fileName, boolean headerPresent) {
      this.fileName = fileName;
      this.headerPresent = headerPresent;
    }

    /**
     * Constructs a {@link CsvReader} object which uses the supplied reader.
     *
     * @param reader the {@link CSVReader} to use
     * @param headerPresent {@code true} if the file's first line is the
     *     header for each column
     */
    public CsvReader(CSVReader reader, boolean headerPresent) {
      this.fileName = null;
      this.reader = reader;
      this.headerPresent = headerPresent;
    }

    /**
     * Creates a {@link CSVReader} for the file and sets the {@code header}
     * if present. After this method is called,
     * {@link #processReader(CsvWorker)} may be called.
     *
     * @throws IOException if the CSV file cannot be read
     */
    private void createCsvReader() throws IOException {
      lineNumber = 1;
      if (reader == null) {
        reader = new CSVReader(Files.newReader(new File(fileName), StandardCharsets.UTF_8));
      }
      if (headerPresent) {
        header = reader.readNext();
        lineNumber++;
      }
    }

    /**
     * Performs the {@link CsvWorker#processLine(String[], String[], int)}
     * method of the {@code worker} parameter for each link in the CSV,
     * and closes the underlying {@link CSVReader}.
     *
     * @param worker the {@code CsvWorker} that performs work on each line
     * @throws IOException if the CSV file cannot be read
     */
    public void processReader(CsvWorker worker) throws IOException {
      createCsvReader();
      try {
        String[] line;
        while ((line = reader.readNext()) != null) {
          worker.processLine(header, line, lineNumber);
          lineNumber++;
        }
      } finally {
        reader.close();
      }
    }

    /**
     * A worker that is called within {@link CsvReader} on each line of the CSV
     * via the {@link #processLine(String[], String[], int)} method.
     */
    private interface CsvWorker {
      /**
       * Processes the current line of the CSV.
       *
       * @param headers the headers usually represented by the first line of the
       *     CSV. If the original file did not contain headers, then
       *     this field may be {@code null}.
       * @param currentLine the current line of the CSV that work will be done on
       * @param currentLineNumber the current one-indexed line number of the CSV
       * @throws IllegalArgumentException if the current line or headers is not
       *     valid to have work performed on
       */
      void processLine(String[] headers, String[] currentLine, int currentLineNumber);
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy