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("header1", "header2", ...);
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}