]> git.argeo.org Git - lgpl/argeo-commons.git/blob - CsvWriter.java
b3f383883970a09ebee6feb624ae6f60cc4f216a
[lgpl/argeo-commons.git] / CsvWriter.java
1 /*
2 * Copyright (C) 2007-2012 Mathieu Baudier
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 import org.argeo.ArgeoException;
27
28 /** Write in CSV format. */
29 public class CsvWriter {
30 private final Writer out;
31
32 private char separator = ',';
33 private char quote = '\"';
34
35 /**
36 * Creates a CSV writer.
37 *
38 * @param out
39 * the stream to write to. Caller is responsible for closing it.
40 */
41 public CsvWriter(OutputStream out) {
42 this.out = new OutputStreamWriter(out);
43 }
44
45 /**
46 * Creates a CSV writer.
47 *
48 * @param out
49 * the stream to write to. Caller is responsible for closing it.
50 */
51 public CsvWriter(OutputStream out, String encoding) {
52 try {
53 this.out = new OutputStreamWriter(out, encoding);
54 } catch (UnsupportedEncodingException e) {
55 throw new ArgeoException("Cannot initialize CSV writer", e);
56 }
57 }
58
59 /**
60 * Write a CSV line. Also used to write a header if needed (this is
61 * transparent for the CSV writer): simply call it first, before writing the
62 * lines.
63 */
64 public void writeLine(List<?> tokens) {
65 try {
66 Iterator<?> it = tokens.iterator();
67 while (it.hasNext()) {
68 writeToken(it.next().toString());
69 if (it.hasNext())
70 out.write(separator);
71 }
72 out.write('\n');
73 out.flush();
74 } catch (IOException e) {
75 throw new ArgeoException("Could not write " + tokens, e);
76 }
77 }
78
79 /**
80 * Write a CSV line. Also used to write a header if needed (this is
81 * transparent for the CSV writer): simply call it first, before writing the
82 * lines.
83 */
84 public void writeLine(Object[] tokens) {
85 try {
86 for (int i = 0; i < tokens.length; i++) {
87 if (tokens[i] == null) {
88 // TODO configure how to deal with null
89 writeToken("");
90 } else {
91 writeToken(tokens[i].toString());
92 }
93 if (i != (tokens.length - 1))
94 out.write(separator);
95 }
96 out.write('\n');
97 out.flush();
98 } catch (IOException e) {
99 throw new ArgeoException("Could not write " + tokens, e);
100 }
101 }
102
103 protected void writeToken(String token) throws IOException {
104 // +2 for possible quotes, another +2 assuming there would be an already
105 // quoted string where quotes needs to be duplicated
106 // another +2 for safety
107 // we don't want to increase buffer size while writing
108 StringBuffer buf = new StringBuffer(token.length() + 6);
109 char[] arr = token.toCharArray();
110 boolean shouldQuote = false;
111 for (char c : arr) {
112 if (!shouldQuote) {
113 if (c == separator)
114 shouldQuote = true;
115 if (c == '\n')
116 shouldQuote = true;
117 }
118
119 if (c == quote) {
120 shouldQuote = true;
121 // duplicate quote
122 buf.append(quote);
123 }
124
125 // generic case
126 buf.append(c);
127 }
128
129 if (shouldQuote == true)
130 out.write(quote);
131 out.write(buf.toString());
132 if (shouldQuote == true)
133 out.write(quote);
134 }
135
136 public void setSeparator(char separator) {
137 this.separator = separator;
138 }
139
140 public void setQuote(char quote) {
141 this.quote = quote;
142 }
143
144 }