diff --git a/pom.xml b/pom.xml
index 262bc17b..8b13c179 100644
--- a/pom.xml
+++ b/pom.xml
@@ -38,6 +38,12 @@ CSV files of various types.
4.12
test
+
+ org.mockito
+ mockito-all
+ 1.9.5
+ test
+
commons-io
commons-io
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index bbfa930e..b56b75f2 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -39,6 +39,7 @@
+ Add autoFlush option for CsvPrinter. PR #24.
withNullString value is printed without quotes when QuoteMode.ALL is specified; add QuoteMode.ALL_NON_NULL. PR #17.
diff --git a/src/main/java/org/apache/commons/csv/CSVFormat.java b/src/main/java/org/apache/commons/csv/CSVFormat.java
index 410c8fb5..29b7c367 100644
--- a/src/main/java/org/apache/commons/csv/CSVFormat.java
+++ b/src/main/java/org/apache/commons/csv/CSVFormat.java
@@ -242,7 +242,7 @@ public final class CSVFormat implements Serializable {
* @see Predefined#Default
*/
public static final CSVFormat DEFAULT = new CSVFormat(COMMA, DOUBLE_QUOTE_CHAR, null, null, null, false, true, CRLF,
- null, null, null, false, false, false, false, false);
+ null, null, null, false, false, false, false, false, false);
/**
* Excel file format (using a comma as the value delimiter). Note that the actual value delimiter used by Excel is
@@ -537,7 +537,7 @@ public final class CSVFormat implements Serializable {
*/
public static CSVFormat newFormat(final char delimiter) {
return new CSVFormat(delimiter, null, null, null, null, false, false, null, null, null, null, false, false,
- false, false, false);
+ false, false, false, false);
}
/**
@@ -584,6 +584,8 @@ public final class CSVFormat implements Serializable {
private final boolean trim;
+ private final boolean autoFlush;
+
/**
* Creates a customized CSV format.
*
@@ -619,15 +621,16 @@ public final class CSVFormat implements Serializable {
* TODO
* @param trailingDelimiter
* TODO
+ * @param autoFlush
* @throws IllegalArgumentException
* if the delimiter is a line break character
*/
private CSVFormat(final char delimiter, final Character quoteChar, final QuoteMode quoteMode,
- final Character commentStart, final Character escape, final boolean ignoreSurroundingSpaces,
- final boolean ignoreEmptyLines, final String recordSeparator, final String nullString,
- final Object[] headerComments, final String[] header, final boolean skipHeaderRecord,
- final boolean allowMissingColumnNames, final boolean ignoreHeaderCase, final boolean trim,
- final boolean trailingDelimiter) {
+ final Character commentStart, final Character escape, final boolean ignoreSurroundingSpaces,
+ final boolean ignoreEmptyLines, final String recordSeparator, final String nullString,
+ final Object[] headerComments, final String[] header, final boolean skipHeaderRecord,
+ final boolean allowMissingColumnNames, final boolean ignoreHeaderCase, final boolean trim,
+ final boolean trailingDelimiter, boolean autoFlush) {
this.delimiter = delimiter;
this.quoteCharacter = quoteChar;
this.quoteMode = quoteMode;
@@ -644,6 +647,7 @@ public final class CSVFormat implements Serializable {
this.ignoreHeaderCase = ignoreHeaderCase;
this.trailingDelimiter = trailingDelimiter;
this.trim = trim;
+ this.autoFlush = autoFlush;
validate();
}
@@ -887,6 +891,16 @@ public final class CSVFormat implements Serializable {
return trim;
}
+ /**
+ * Returns whether to flush on close.
+ *
+ * @return whether to flush on close.
+ * @since 1.6
+ */
+ public boolean getAutoFlush() {
+ return autoFlush;
+ }
+
@Override
public int hashCode() {
final int prime = 31;
@@ -1431,7 +1445,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withAllowMissingColumnNames(final boolean allowMissingColumnNames) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1466,7 +1480,7 @@ public final class CSVFormat implements Serializable {
}
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1484,7 +1498,7 @@ public final class CSVFormat implements Serializable {
}
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1515,7 +1529,7 @@ public final class CSVFormat implements Serializable {
}
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escape, ignoreSurroundingSpaces,
ignoreEmptyLines, recordSeparator, nullString, headerComments, header, skipHeaderRecord,
- allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1670,7 +1684,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withHeader(final String... header) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1691,7 +1705,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withHeaderComments(final Object... headerComments) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1716,7 +1730,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withIgnoreEmptyLines(final boolean ignoreEmptyLines) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1742,7 +1756,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withIgnoreHeaderCase(final boolean ignoreHeaderCase) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1767,7 +1781,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withIgnoreSurroundingSpaces(final boolean ignoreSurroundingSpaces) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1786,7 +1800,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withNullString(final String nullString) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1817,7 +1831,7 @@ public final class CSVFormat implements Serializable {
}
return new CSVFormat(delimiter, quoteChar, quoteMode, commentMarker, escapeCharacter, ignoreSurroundingSpaces,
ignoreEmptyLines, recordSeparator, nullString, headerComments, header, skipHeaderRecord,
- allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1831,7 +1845,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withQuoteMode(final QuoteMode quoteModePolicy) {
return new CSVFormat(delimiter, quoteCharacter, quoteModePolicy, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1869,7 +1883,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withRecordSeparator(final String recordSeparator) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1896,7 +1910,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withSkipHeaderRecord(final boolean skipHeaderRecord) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1921,7 +1935,7 @@ public final class CSVFormat implements Serializable {
public CSVFormat withTrailingDelimiter(final boolean trailingDelimiter) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
/**
@@ -1946,6 +1960,21 @@ public final class CSVFormat implements Serializable {
public CSVFormat withTrim(final boolean trim) {
return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
- skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter);
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
+ }
+
+ /**
+ * Returns a new {@code CSVFormat} with whether to flush on close.
+ *
+ * @param autoFlush
+ * whether to flush on close.
+ *
+ * @return A new CSVFormat that is equal to this but with the specified autoFlush setting.
+ * @since 1.6
+ */
+ public CSVFormat withAutoFlush(final boolean autoFlush) {
+ return new CSVFormat(delimiter, quoteCharacter, quoteMode, commentMarker, escapeCharacter,
+ ignoreSurroundingSpaces, ignoreEmptyLines, recordSeparator, nullString, headerComments, header,
+ skipHeaderRecord, allowMissingColumnNames, ignoreHeaderCase, trim, trailingDelimiter, autoFlush);
}
}
diff --git a/src/main/java/org/apache/commons/csv/CSVPrinter.java b/src/main/java/org/apache/commons/csv/CSVPrinter.java
index 96b24a41..49d9022c 100644
--- a/src/main/java/org/apache/commons/csv/CSVPrinter.java
+++ b/src/main/java/org/apache/commons/csv/CSVPrinter.java
@@ -81,6 +81,23 @@ public final class CSVPrinter implements Flushable, Closeable {
@Override
public void close() throws IOException {
+ close(false);
+ }
+
+ /**
+ * Closes the underlying stream with an optional flush first.
+ * @param flush whether to flush before the actual close.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ * @since 1.6
+ */
+ public void close(boolean flush) throws IOException {
+ if (flush || format.getAutoFlush()) {
+ if (out instanceof Flushable) {
+ ((Flushable) out).flush();
+ }
+ }
if (out instanceof Closeable) {
((Closeable) out).close();
}
diff --git a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java
index 4a0ffbff..893675cd 100644
--- a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java
+++ b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java
@@ -21,12 +21,17 @@ import static org.apache.commons.csv.Constants.CR;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
+import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.sql.BatchUpdateException;
@@ -1311,4 +1316,54 @@ public class CSVPrinterTest {
}
}
+ @Test
+ public void testCloseWithFlushOn() throws IOException {
+ Writer writer = mock(Writer.class);
+ CSVFormat csvFormat = CSVFormat.DEFAULT;
+ CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat);
+ csvPrinter.close(true);
+ verify(writer, times(1)).flush();
+ }
+
+ @Test
+ public void testCloseWithFlushOff() throws IOException {
+ Writer writer = mock(Writer.class);
+ CSVFormat csvFormat = CSVFormat.DEFAULT;
+ CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat);
+ csvPrinter.close(false);
+ verify(writer, never()).flush();
+ verify(writer, times(1)).close();
+ }
+
+ @Test
+ public void testCloseBackwardCompatibility() throws IOException {
+ Writer writer = mock(Writer.class);
+ CSVFormat csvFormat = CSVFormat.DEFAULT;
+ try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) {
+ }
+ verify(writer, never()).flush();
+ verify(writer, times(1)).close();
+ }
+
+ @Test
+ public void testCloseWithCsvFormatAutoFlushOn() throws IOException {
+ System.out.println("start method");
+ Writer writer = mock(Writer.class);
+ CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(true);
+ try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) {
+ }
+ verify(writer, times(1)).flush();
+ verify(writer, times(1)).close();
+ }
+
+ @Test
+ public void testCloseWithCsvFormatAutoFlushOff() throws IOException {
+ Writer writer = mock(Writer.class);
+ CSVFormat csvFormat = CSVFormat.DEFAULT.withAutoFlush(false);
+ try (CSVPrinter csvPrinter = new CSVPrinter(writer, csvFormat)) {
+ }
+ verify(writer, never()).flush();
+ verify(writer, times(1)).close();
+ }
+
}