DelimitedWriter.java

    1/*******************************************************************************
    2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
    3 * All rights reserved. This program and the accompanying materials
    4 * are made available under the terms of the Eclipse Public License v1.0
    5 * which accompanies this distribution, and is available at
    6 * http://www.eclipse.org/legal/epl-v10.html
    7 *
    8 * Contributors:
    9 *    Brock Janiczak - initial API and implementation
   10 *    
   11 *******************************************************************************/
   12package org.jacoco.report.csv;
   13
   14import java.io.IOException;
   15import java.io.Writer;
   16
   17/**
   18 * Helper class for writing out CSV or tab delimited files.
   19 * <p>
   20 * <strong>Example Usage:</strong>
   21 * 
   22 * <pre>
   23 * delimitedWriter.writeFields(&quot;header1&quot;, &quot;header2&quot;, ...);
   24 * for each line to be written {
   25 *   delimitedWriter.writeField(value1);
   26 *   delimitedWriter.writeField(value2);
   27 *   delimitedWriter.nextLine();
   28 * }
   29 * delimitedWriter.close();
   30 * </pre>
   31 * 
   32 * </p>
   33 * 
   34 * @author Brock Janiczak
   35 * @version 0.4.1.20101007204400
   36 */
   37public class DelimitedWriter {
   38    private static final String QUOTE = "\"";
   39    private static final String ESCAPED_QUOTE = "\"\"";
   40
   41    private static final char DEFAULT_DELIMITER = ',';
   42    private static final String NEW_LINE = System.getProperty("line.separator");
   43    private final char delimiter;
   44    private final Writer delegate;
   45    private int fieldPosition = 0;
   46
   47    /**
   48     * Creates a new Delimited writer using the default delimiter
   49     * 
   50     * @param delegate
   51     *            Writer to delegate all writes to
   52     */
   53    public DelimitedWriter(final Writer delegate) {
   54        this(delegate, DEFAULT_DELIMITER);
   55    }
   56
   57    /**
   58     * Creates a new Delimited writer using the default delimiter
   59     * 
   60     * @param delegate
   61     *            Writer to delegate all writes to
   62     * @param delimiter
   63     *            delimiter to use (usually a comma, tab or space)
   64     */
   65    public DelimitedWriter(final Writer delegate, final char delimiter) {
   66        this.delegate = delegate;
   67        this.delimiter = delimiter;
   68    }
   69
   70    /**
   71     * Write multiple fields at once. Values will be auto escaped and quoted as
   72     * needed. Each value will be separated using the current delimiter
   73     * 
   74     * @param fields
   75     *            Values to write
   76     * @throws IOException
   77     *             Error writing to the underlying writer object
   78     */
   79    public void write(final String... fields) throws IOException {
   80        for (final String field : fields) {
   81            write(field);
   82        }
   83    }
   84
   85    /**
   86     * Write a single value. Values will be auto escaped and quoted as needed.
   87     * If this is not the first field of the current line the value will be
   88     * prepended with the current delimiter
   89     * 
   90     * @param field
   91     *            Value to write
   92     * @throws IOException
   93     *             Error writing to the underlying writer object
   94     */
   95    public void write(final String field) throws IOException {
   96        if (fieldPosition != 0) {
   97            delegate.write(delimiter);
   98        }
   99        delegate.write(escape(field));
  100        fieldPosition++;
  101    }
  102
  103    /**
  104     * Write a single integer value.
  105     * 
  106     * @param value
  107     *            Value to write
  108     * @throws IOException
  109     *             Error writing to the underlying writer object
  110     */
  111    public void write(final int value) throws IOException {
  112        write(Integer.toString(value));
  113    }
  114
  115    /**
  116     * Write muliple integer values
  117     * 
  118     * @param values
  119     *            values to write
  120     * @throws IOException
  121     *             Error writing to the underlying writer object
  122     */
  123    public void write(final int... values) throws IOException {
  124        for (final int value : values) {
  125            write(Integer.toString(value));
  126        }
  127    }
  128
  129    /**
  130     * Output a new line and advance the writer to the next line. The line
  131     * delimiter is the default for the platform.
  132     * 
  133     * @throws IOException
  134     *             Error writing to the underlying writer object
  135     */
  136    public void nextLine() throws IOException {
  137        delegate.write(NEW_LINE);
  138        fieldPosition = 0;
  139    }
  140
  141    /**
  142     * Close the underlying writer object. Once closed all write operations will
  143     * fail
  144     * 
  145     * @throws IOException
  146     *             Error closing the underlying writer object
  147     */
  148    public void close() throws IOException {
  149        delegate.close();
  150    }
  151
  152    /**
  153     * Escapes any occurrences of the quote character in value by replacing it
  154     * with a double quote. Also Quotes the value if a quote or delimiter value
  155     * is found.
  156     * 
  157     * @param value
  158     *            String that needs escaping
  159     * @return New string with all values escaped
  160     */
  161    private String escape(final String value) {
  162        String escapedValue = value;
  163
  164        // Escape and quote if the source value contains the delimiter
  165        // or the quote character
  166        if (value.indexOf(QUOTE) != -1 || value.indexOf(delimiter) != -1) {
  167            escapedValue = value.replace(QUOTE, ESCAPED_QUOTE);
  168            escapedValue = QUOTE + escapedValue + QUOTE;
  169        }
  170
  171        return escapedValue;
  172    }
  173}