View Javadoc
1   /*
2    * Copyright (C) 2007-2012 Argeo GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.argeo.util;
17  
18  import java.io.IOException;
19  import java.io.OutputStream;
20  import java.io.OutputStreamWriter;
21  import java.io.UnsupportedEncodingException;
22  import java.io.Writer;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  /** Write in CSV format. */
27  public class CsvWriter {
28  	private final Writer out;
29  
30  	private char separator = ',';
31  	private char quote = '\"';
32  
33  	/**
34  	 * Creates a CSV writer.
35  	 * 
36  	 * @param out
37  	 *            the stream to write to. Caller is responsible for closing it.
38  	 */
39  	public CsvWriter(OutputStream out) {
40  		this.out = new OutputStreamWriter(out);
41  	}
42  
43  	/**
44  	 * Creates a CSV writer.
45  	 * 
46  	 * @param out
47  	 *            the stream to write to. Caller is responsible for closing it.
48  	 */
49  	public CsvWriter(OutputStream out, String encoding) {
50  		try {
51  			this.out = new OutputStreamWriter(out, encoding);
52  		} catch (UnsupportedEncodingException e) {
53  			throw new UtilsException("Cannot initialize CSV writer", e);
54  		}
55  	}
56  
57  	/**
58  	 * Write a CSV line. Also used to write a header if needed (this is
59  	 * transparent for the CSV writer): simply call it first, before writing the
60  	 * lines.
61  	 */
62  	public void writeLine(List<?> tokens) {
63  		try {
64  			Iterator<?> it = tokens.iterator();
65  			while (it.hasNext()) {
66  				writeToken(it.next().toString());
67  				if (it.hasNext())
68  					out.write(separator);
69  			}
70  			out.write('\n');
71  			out.flush();
72  		} catch (IOException e) {
73  			throw new UtilsException("Could not write " + tokens, e);
74  		}
75  	}
76  
77  	/**
78  	 * Write a CSV line. Also used to write a header if needed (this is
79  	 * transparent for the CSV writer): simply call it first, before writing the
80  	 * lines.
81  	 */
82  	public void writeLine(Object[] tokens) {
83  		try {
84  			for (int i = 0; i < tokens.length; i++) {
85  				if (tokens[i] == null) {
86  					// TODO configure how to deal with null
87  					writeToken("");
88  				} else {
89  					writeToken(tokens[i].toString());
90  				}
91  				if (i != (tokens.length - 1))
92  					out.write(separator);
93  			}
94  			out.write('\n');
95  			out.flush();
96  		} catch (IOException e) {
97  			throw new UtilsException("Could not write " + tokens, e);
98  		}
99  	}
100 
101 	protected void writeToken(String token) throws IOException {
102 		// +2 for possible quotes, another +2 assuming there would be an already
103 		// quoted string where quotes needs to be duplicated
104 		// another +2 for safety
105 		// we don't want to increase buffer size while writing
106 		StringBuffer buf = new StringBuffer(token.length() + 6);
107 		char[] arr = token.toCharArray();
108 		boolean shouldQuote = false;
109 		for (char c : arr) {
110 			if (!shouldQuote) {
111 				if (c == separator)
112 					shouldQuote = true;
113 				if (c == '\n')
114 					shouldQuote = true;
115 			}
116 
117 			if (c == quote) {
118 				shouldQuote = true;
119 				// duplicate quote
120 				buf.append(quote);
121 			}
122 
123 			// generic case
124 			buf.append(c);
125 		}
126 
127 		if (shouldQuote == true)
128 			out.write(quote);
129 		out.write(buf.toString());
130 		if (shouldQuote == true)
131 			out.write(quote);
132 	}
133 
134 	public void setSeparator(char separator) {
135 		this.separator = separator;
136 	}
137 
138 	public void setQuote(char quote) {
139 		this.quote = quote;
140 	}
141 
142 }