View Javadoc
1   package com.opencsv;
2   
3   /*
4    Copyright 2015 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.IOException;
20  import java.io.Writer;
21  
22  /**
23   * A very simple CSV writer released under a commercial-friendly license.
24   *
25   * @author Glen Smith
26   */
27  public class CSVWriter extends AbstractCSVWriter {
28  
29     protected final char separator;
30     protected final char quotechar;
31     protected final char escapechar;
32  
33     /**
34      * Constructs CSVWriter using a comma for the separator.
35      *
36      * @param writer The writer to an underlying CSV source.
37      */
38     public CSVWriter(Writer writer) {
39        this(writer, DEFAULT_SEPARATOR, DEFAULT_QUOTE_CHARACTER, DEFAULT_ESCAPE_CHARACTER, DEFAULT_LINE_END);
40     }
41  
42     /**
43      * Constructs CSVWriter with supplied separator, quote char, escape char and line ending.
44      *
45      * @param writer     The writer to an underlying CSV source.
46      * @param separator  The delimiter to use for separating entries
47      * @param quotechar  The character to use for quoted elements
48      * @param escapechar The character to use for escaping quotechars or escapechars
49      * @param lineEnd    The line feed terminator to use
50      */
51     public CSVWriter(Writer writer, char separator, char quotechar, char escapechar, String lineEnd) {
52        super(writer, lineEnd);
53        this.escapechar = escapechar;
54        this.quotechar = quotechar;
55        this.separator = separator;
56     }
57  
58  
59     @Override
60     protected void writeNext(String[] nextLine, boolean applyQuotesToAll, Appendable appendable) throws IOException {
61        if (nextLine == null) {
62           return;
63        }
64  
65        for (int i = 0; i < nextLine.length; i++) {
66  
67           if (i != 0) {
68              appendable.append(separator);
69           }
70  
71           String nextElement = nextLine[i];
72  
73           if (nextElement == null) {
74              continue;
75           }
76  
77           Boolean stringContainsSpecialCharacters = stringContainsSpecialCharacters(nextElement);
78  
79           appendQuoteCharacterIfNeeded(applyQuotesToAll, appendable, stringContainsSpecialCharacters);
80  
81           if (stringContainsSpecialCharacters) {
82              processLine(nextElement, appendable);
83           } else {
84              appendable.append(nextElement);
85           }
86  
87           appendQuoteCharacterIfNeeded(applyQuotesToAll, appendable, stringContainsSpecialCharacters);
88        }
89  
90        appendable.append(lineEnd);
91        writer.write(appendable.toString());
92     }
93  
94     private void appendQuoteCharacterIfNeeded(boolean applyQuotesToAll, Appendable appendable, Boolean stringContainsSpecialCharacters) throws IOException {
95        if ((applyQuotesToAll || stringContainsSpecialCharacters) && quotechar != NO_QUOTE_CHARACTER) {
96           appendable.append(quotechar);
97        }
98     }
99  
100    /**
101     * Checks to see if the line contains special characters.
102     * @param line Element of data to check for special characters.
103     * @return True if the line contains the quote, escape, separator, newline, or return.
104     */
105    protected boolean stringContainsSpecialCharacters(String line) {
106       return line.indexOf(quotechar) != -1
107               || line.indexOf(escapechar) != -1
108               || line.indexOf(separator) != -1
109               || line.contains(DEFAULT_LINE_END)
110               || line.contains("\r");
111    }
112 
113    /**
114     * Processes all the characters in a line.
115     * @param nextElement Element to process.
116     * @param appendable - Appendable holding the processed data.
117     * @throws IOException - IOException thrown by the writer supplied to the CSVWriter
118     */
119    protected void processLine(String nextElement, Appendable appendable) throws IOException {
120       for (int j = 0; j < nextElement.length(); j++) {
121          char nextChar = nextElement.charAt(j);
122          processCharacter(appendable, nextChar);
123       }
124    }
125 
126    /**
127     * Appends the character to the StringBuilder adding the escape character if needed.
128     * @param appendable - Appendable holding the processed data.
129     * @param nextChar Character to process
130     * @throws IOException - IOException thrown by the writer supplied to the CSVWriter.
131     */
132    protected void processCharacter(Appendable appendable, char nextChar) throws IOException {
133       if (escapechar != NO_ESCAPE_CHARACTER && checkCharactersToEscape(nextChar)) {
134          appendable.append(escapechar);
135       }
136       appendable.append(nextChar);
137    }
138 
139    /**
140     * Checks whether the next character that is to be written out is a special
141     * character that must be quoted.
142     * The quote character, escape charater, and separator are special characters.
143     *
144     * @param nextChar The next character to be written
145     * @return Whether the character needs to be quoted or not
146     */
147    protected boolean checkCharactersToEscape(char nextChar) {
148       return quotechar == NO_QUOTE_CHARACTER
149               ? (nextChar == quotechar || nextChar == escapechar || nextChar == separator || nextChar == '\n')
150               : (nextChar == quotechar || nextChar == escapechar);
151    }
152 
153 }