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