View Javadoc

1   package au.com.bytecode.opencsv;
2   
3   /**
4    Copyright 2005 Bytecode Pty Ltd.
5   
6    Licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8    You may obtain a copy of the License at
9   
10   http://www.apache.org/licenses/LICENSE-2.0
11  
12   Unless required by applicable law or agreed to in writing, software
13   distributed under the License is distributed on an "AS IS" BASIS,
14   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   See the License for the specific language governing permissions and
16   limitations under the License.
17   */
18  
19  import java.io.*;
20  import java.sql.ResultSet;
21  import java.sql.SQLException;
22  import java.util.List;
23  
24  /**
25   * A very simple CSV writer released under a commercial-friendly license.
26   *
27   * @author Glen Smith
28   */
29  public class CSVWriter implements Closeable, Flushable {
30  
31      public static final int INITIAL_STRING_SIZE = 128;
32  
33      private Writer rawWriter;
34  
35      private PrintWriter pw;
36  
37      private char separator;
38  
39      private char quotechar;
40  
41      private char escapechar;
42  
43      private String lineEnd;
44  
45      /**
46       * The character used for escaping quotes.
47       */
48      public static final char DEFAULT_ESCAPE_CHARACTER = '"';
49  
50      /**
51       * The default separator to use if none is supplied to the constructor.
52       */
53      public static final char DEFAULT_SEPARATOR = ',';
54  
55      /**
56       * The default quote character to use if none is supplied to the
57       * constructor.
58       */
59      public static final char DEFAULT_QUOTE_CHARACTER = '"';
60  
61      /**
62       * The quote constant to use when you wish to suppress all quoting.
63       */
64      public static final char NO_QUOTE_CHARACTER = '\u0000';
65  
66      /**
67       * The escape constant to use when you wish to suppress all escaping.
68       */
69      public static final char NO_ESCAPE_CHARACTER = '\u0000';
70  
71      /**
72       * Default line terminator uses platform encoding.
73       */
74      public static final String DEFAULT_LINE_END = "\n";
75  
76      private ResultSetHelper resultService = new ResultSetHelperService();
77  
78      /**
79       * Constructs CSVWriter using a comma for the separator.
80       *
81       * @param writer the writer to an underlying CSV source.
82       */
83      public CSVWriter(Writer writer) {
84          this(writer, DEFAULT_SEPARATOR);
85      }
86  
87      /**
88       * Constructs CSVWriter with supplied separator.
89       *
90       * @param writer    the writer to an underlying CSV source.
91       * @param separator the delimiter to use for separating entries.
92       */
93      public CSVWriter(Writer writer, char separator) {
94          this(writer, separator, DEFAULT_QUOTE_CHARACTER);
95      }
96  
97      /**
98       * Constructs CSVWriter with supplied separator and quote char.
99       *
100      * @param writer    the writer to an underlying CSV source.
101      * @param separator the delimiter to use for separating entries
102      * @param quotechar the character to use for quoted elements
103      */
104     public CSVWriter(Writer writer, char separator, char quotechar) {
105         this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER);
106     }
107 
108     /**
109      * Constructs CSVWriter with supplied separator and quote char.
110      *
111      * @param writer     the writer to an underlying CSV source.
112      * @param separator  the delimiter to use for separating entries
113      * @param quotechar  the character to use for quoted elements
114      * @param escapechar the character to use for escaping quotechars or escapechars
115      */
116     public CSVWriter(Writer writer, char separator, char quotechar, char escapechar) {
117         this(writer, separator, quotechar, escapechar, DEFAULT_LINE_END);
118     }
119 
120 
121     /**
122      * Constructs CSVWriter with supplied separator and quote char.
123      *
124      * @param writer    the writer to an underlying CSV source.
125      * @param separator the delimiter to use for separating entries
126      * @param quotechar the character to use for quoted elements
127      * @param lineEnd   the line feed terminator to use
128      */
129     public CSVWriter(Writer writer, char separator, char quotechar, String lineEnd) {
130         this(writer, separator, quotechar, DEFAULT_ESCAPE_CHARACTER, lineEnd);
131     }
132 
133 
134     /**
135      * Constructs CSVWriter with supplied separator, quote char, escape char and line ending.
136      *
137      * @param writer     the writer to an underlying CSV source.
138      * @param separator  the delimiter to use for separating entries
139      * @param quotechar  the character to use for quoted elements
140      * @param escapechar the character to use for escaping quotechars or escapechars
141      * @param lineEnd    the line feed terminator to use
142      */
143     public CSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) {
144         this.rawWriter = writer;
145         this.pw = new PrintWriter(writer);
146         this.separator = separator;
147         this.quotechar = quotechar;
148         this.escapechar = escapechar;
149         this.lineEnd = lineEnd;
150     }
151 
152     /**
153      * Writes the entire list to a CSV file. The list is assumed to be a
154      * String[]
155      *
156      * @param allLines         a List of String[], with each String[] representing a line of
157      *                         the file.
158      * @param applyQuotesToAll true if all values are to be quoted.  false if quotes only
159      *                         to be applied to values which contain the separator, escape,
160      *                         quote or new line characters.
161      */
162     public void writeAll(List<String[]> allLines, boolean applyQuotesToAll) {
163         for (String[] line : allLines) {
164             writeNext(line, applyQuotesToAll);
165         }
166     }
167 
168     /**
169      * Writes the entire list to a CSV file. The list is assumed to be a
170      * String[]
171      *
172      * @param allLines a List of String[], with each String[] representing a line of
173      *                 the file.
174      */
175     public void writeAll(List<String[]> allLines) {
176         for (String[] line : allLines) {
177             writeNext(line);
178         }
179     }
180 
181     protected void writeColumnNames(ResultSet rs)
182             throws SQLException {
183 
184         writeNext(resultService.getColumnNames(rs));
185     }
186 
187     /**
188      * Writes the entire ResultSet to a CSV file.
189      * <p/>
190      * The caller is responsible for closing the ResultSet.
191      *
192      * @param rs                 the recordset to write
193      * @param includeColumnNames true if you want column names in the output, false otherwise
194      * @throws java.io.IOException   thrown by getColumnValue
195      * @throws java.sql.SQLException thrown by getColumnValue
196      */
197     public void writeAll(java.sql.ResultSet rs, boolean includeColumnNames) throws SQLException, IOException {
198         writeAll(rs, includeColumnNames, false);
199     }
200 
201     /**
202      * Writes the entire ResultSet to a CSV file.
203      * <p/>
204      * The caller is responsible for closing the ResultSet.
205      *
206      * @throws java.io.IOException   thrown by getColumnValue
207      * @throws java.sql.SQLException thrown by getColumnValue
208      */
209     public void writeAll(java.sql.ResultSet rs, boolean includeColumnNames, boolean trim) throws SQLException, IOException {
210 
211 
212         if (includeColumnNames) {
213             writeColumnNames(rs);
214         }
215 
216         while (rs.next()) {
217             writeNext(resultService.getColumnValues(rs, trim));
218         }
219     }
220 
221     /**
222      * Writes the next line to the file.
223      *
224      * @param nextLine         a string array with each comma-separated element as a separate
225      *                         entry.
226      * @param applyQuotesToAll true if all values are to be quoted.  false applies quotes only
227      *                         to values which contain the separator, escape, quote or new line characters.
228      */
229     public void writeNext(String[] nextLine, boolean applyQuotesToAll) {
230 
231         if (nextLine == null)
232             return;
233 
234         StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
235         for (int i = 0; i < nextLine.length; i++) {
236 
237             if (i != 0) {
238                 sb.append(separator);
239             }
240 
241             String nextElement = nextLine[i];
242 
243             if (nextElement == null)
244                 continue;
245 
246             Boolean stringContainsSpecialCharacters = stringContainsSpecialCharacters(nextElement);
247 
248             if ((applyQuotesToAll || stringContainsSpecialCharacters) && quotechar != NO_QUOTE_CHARACTER)
249                 sb.append(quotechar);
250 
251             if (stringContainsSpecialCharacters) {
252                 sb.append(processLine(nextElement));
253             } else {
254                 sb.append(nextElement);
255             }
256 
257             if ((applyQuotesToAll || stringContainsSpecialCharacters) && quotechar != NO_QUOTE_CHARACTER)
258                 sb.append(quotechar);
259         }
260 
261         sb.append(lineEnd);
262         pw.write(sb.toString());
263     }
264 
265     /**
266      * Writes the next line to the file.
267      *
268      * @param nextLine a string array with each comma-separated element as a separate
269      *                 entry.
270      */
271     public void writeNext(String[] nextLine) {
272         writeNext(nextLine, true);
273     }
274 
275     private boolean stringContainsSpecialCharacters(String line) {
276         return line.indexOf(quotechar) != -1 || line.indexOf(escapechar) != -1 || line.indexOf(separator) != -1 || line.indexOf("\n") != -1 || line.indexOf("\r") != -1;
277     }
278 
279     protected StringBuilder processLine(String nextElement) {
280         StringBuilder sb = new StringBuilder(INITIAL_STRING_SIZE);
281         for (int j = 0; j < nextElement.length(); j++) {
282             char nextChar = nextElement.charAt(j);
283             if (escapechar != NO_ESCAPE_CHARACTER && nextChar == quotechar) {
284                 sb.append(escapechar).append(nextChar);
285             } else if (escapechar != NO_ESCAPE_CHARACTER && nextChar == escapechar) {
286                 sb.append(escapechar).append(nextChar);
287             } else {
288                 sb.append(nextChar);
289             }
290         }
291 
292         return sb;
293     }
294 
295     /**
296      * Flush underlying stream to writer.
297      *
298      * @throws IOException if bad things happen
299      */
300     public void flush() throws IOException {
301 
302         pw.flush();
303 
304     }
305 
306     /**
307      * Close the underlying stream writer flushing any buffered content.
308      *
309      * @throws IOException if bad things happen
310      */
311     public void close() throws IOException {
312         flush();
313         pw.close();
314         rawWriter.close();
315     }
316 
317     /**
318      * Checks to see if the there has been an error in the printstream.
319      */
320     public boolean checkError() {
321         return pw.checkError();
322     }
323 
324     public void setResultService(ResultSetHelper resultService) {
325         this.resultService = resultService;
326     }
327 
328     public void flushQuietly() {
329         try {
330             flush();
331         } catch (IOException e) {
332             // catch exception and ignore.
333         }
334     }
335 }