001package gudusoft.gsqlparser.util.csv; 002 003import java.io.*; 004import java.nio.charset.Charset; 005 006public class CsvWriter { 007 008 private Writer outWriter; 009 private char sepChar = ','; 010 private char recDelimiterChar = '\n'; 011 private char textQuoteChar = '"'; 012 private boolean enableTextQuote = true; 013 private boolean forceTextQuote = false; 014 private char commentSymbol = '#'; 015 private int escMode = ESCAPE_MODE_DOUBLED; 016 private boolean isFirstColumn = true; 017 private boolean isClosed = false; 018 private boolean customRecDelimiter = false; 019 020 public static final int ESCAPE_MODE_DOUBLED = 1; 021 public static final int ESCAPE_MODE_BACKSLASH = 2; 022 023 public CsvWriter(String fileName, char delimiter, Charset charset) { 024 if (fileName == null || charset == null) { 025 throw new IllegalArgumentException("Parameters cannot be null"); 026 } 027 try { 028 this.outWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), charset)); 029 } catch (IOException e) { 030 throw new RuntimeException(e); 031 } 032 this.sepChar = delimiter; 033 } 034 035 public CsvWriter(String fileName) { 036 this(fileName, ',', Charset.forName("ISO-8859-1")); 037 } 038 039 public CsvWriter(Writer writer, char delimiter) { 040 if (writer == null) throw new IllegalArgumentException("Writer cannot be null"); 041 this.outWriter = writer; 042 this.sepChar = delimiter; 043 } 044 045 public CsvWriter(OutputStream stream, char delimiter, Charset charset) { 046 this(new OutputStreamWriter(stream, charset), delimiter); 047 } 048 049 public char getDelimiter() { return sepChar; } 050 public void setDelimiter(char delimiter) { this.sepChar = delimiter; } 051 052 public char getRecordDelimiter() { return recDelimiterChar; } 053 public void setRecordDelimiter(char recDelimiter) { 054 this.recDelimiterChar = recDelimiter; 055 this.customRecDelimiter = true; 056 } 057 058 public char getTextQualifier() { return textQuoteChar; } 059 public void setTextQualifier(char textQualifier) { this.textQuoteChar = textQualifier; } 060 061 public boolean getUseTextQualifier() { return enableTextQuote; } 062 public void setUseTextQualifier(boolean useTextQualifier) { this.enableTextQuote = useTextQualifier; } 063 064 public int getEscapeMode() { return escMode; } 065 public void setEscapeMode(int escapeMode) { this.escMode = escapeMode; } 066 067 public char getComment() { return commentSymbol; } 068 public void setComment(char comment) { this.commentSymbol = comment; } 069 070 public boolean getForceQualifier() { return forceTextQuote; } 071 public void setForceQualifier(boolean forceQualifier) { this.forceTextQuote = forceQualifier; } 072 073 public void write(String content, boolean preserveSpaces) throws IOException { 074 checkClosed(); 075 if (content == null) content = ""; 076 077 if (!isFirstColumn) outWriter.write(sepChar); 078 079 boolean quote = forceTextQuote; 080 String value = preserveSpaces ? content : content.trim(); 081 082 if (enableTextQuote && !quote) { 083 if (value.indexOf(sepChar) >= 0 || value.indexOf(textQuoteChar) >= 0 || 084 (!customRecDelimiter && (value.indexOf('\n') >= 0 || value.indexOf('\r') >= 0)) || 085 (customRecDelimiter && value.indexOf(recDelimiterChar) >= 0) || 086 (isFirstColumn && value.length() > 0 && value.charAt(0) == commentSymbol) || 087 (isFirstColumn && value.isEmpty()) 088 ) { 089 quote = true; 090 } 091 } 092 093 if (quote) { 094 outWriter.write(textQuoteChar); 095 value = escapeValue(value); 096 } else if (escMode == ESCAPE_MODE_BACKSLASH) { 097 value = escapeWithBackslash(value); 098 } 099 100 outWriter.write(value); 101 102 if (quote) outWriter.write(textQuoteChar); 103 104 isFirstColumn = false; 105 } 106 107 public void write(String content) throws IOException { 108 write(content, false); 109 } 110 111 public void writeComment(String commentText) throws IOException { 112 checkClosed(); 113 outWriter.write(commentSymbol); 114 outWriter.write(commentText); 115 outWriter.write(customRecDelimiter ? recDelimiterChar : '\n'); 116 isFirstColumn = true; 117 } 118 119 public void writeRecord(String[] values, boolean preserveSpaces) throws IOException { 120 if (values != null && values.length > 0) { 121 for (String val : values) { 122 write(val, preserveSpaces); 123 } 124 endRecord(); 125 } 126 } 127 128 public void writeRecord(String[] values) throws IOException { 129 writeRecord(values, false); 130 } 131 132 public void endRecord() throws IOException { 133 checkClosed(); 134 outWriter.write(customRecDelimiter ? recDelimiterChar : '\n'); 135 isFirstColumn = true; 136 } 137 138 public void flush() throws IOException { outWriter.flush(); } 139 140 public void close() { 141 if (!isClosed) { 142 try { 143 outWriter.close(); 144 } catch (Exception ignored) {} 145 isClosed = true; 146 } 147 } 148 149 private void checkClosed() throws IOException { 150 if (isClosed) throw new IOException("CsvWriter already closed."); 151 } 152 153 private String escapeValue(String val) { 154 if (escMode == ESCAPE_MODE_DOUBLED) { 155 return val.replace("" + textQuoteChar, "" + textQuoteChar + textQuoteChar); 156 } 157 return val; 158 } 159 160 private String escapeWithBackslash(String val) { 161 val = val.replace("\\", "\\\\") 162 .replace("" + textQuoteChar, "\\" + textQuoteChar) 163 .replace("" + sepChar, "\\" + sepChar); 164 if (!customRecDelimiter) { 165 val = val.replace("\n", "\\n").replace("\r", "\\r"); 166 } else { 167 val = val.replace("" + recDelimiterChar, "\\" + recDelimiterChar); 168 } 169 if (isFirstColumn && val.length() > 0 && val.charAt(0) == commentSymbol) { 170 val = "\\" + val; 171 } 172 return val; 173 } 174}