CSVPrinter.java Source Code

  • CSV Documentation and Examples
  • CSVPrinter Javadoc
    /*
     * Copyright (C) 2001-2010 Stephen Ostermiller
     * http://ostermiller.org/contact.pl?regarding=Java+Utilities
     *
     * Copyright (C) 2003 Pierre Dittgen <pierre dot dittgen at pass-tech dot fr>
     *
     * This program is free software; you can redistribute it and/or modify
     * it under the terms of the GNU General Public License as published by
     * the Free Software Foundation; either version 2 of the License, or
     * (at your option) any later version.
     *
     * This program is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     * GNU General Public License for more details.
     *
     * See LICENSE.txt for details.
     */
    
    package com.Ostermiller.util;
    import java.io.*;
    
    /**
     * Print values as a comma separated list.
     * More information about this class is available from <a target="_top" href=
     * "http://ostermiller.org/utils/CSV.html">ostermiller.org</a>.
     *
     * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities
     * @author Pierre Dittgen <pierre dot dittgen at pass-tech dot fr>
     * @since ostermillerutils 1.00.00
     */
    public class CSVPrinter implements CSVPrint {
    
    	/**
    	 * Default state of auto flush
    	 */
    	private static final boolean AUTO_FLUSH_DEFAULT = true;
    
    	/**
    	 * If auto flushing is enabled.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	protected boolean autoFlush = AUTO_FLUSH_DEFAULT;
    
    	/**
    	 * Default state of always quote
    	 */
    	private static final boolean ALWAYS_QUOTE_DEFAULT = false;
    
    	/**
    	 * If auto flushing is enabled.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	protected boolean alwaysQuote = ALWAYS_QUOTE_DEFAULT;
    
    	/**
    	 * true iff an error has occurred.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	protected boolean error = false;
    
    	/**
    	 * Default delimiter character
    	 */
    	private static final char DELIMITER_DEFAULT = ',';
    
    	/**
    	 * Character written as field delimiter.
    	 *
    	 * @since ostermillerutils 1.02.18
    	 */
    	protected char delimiterChar = DELIMITER_DEFAULT;
    
    	/**
    	 * Default quoting character
    	 */
    	private static final char QUOTE_DEFAULT = '"';
    
    	/**
    	 * Quoting character.
    	 *
    	 * @since ostermillerutils 1.02.18
    	 */
    	protected char quoteChar = QUOTE_DEFAULT;
    
    	/**
    	 * The place that the values get written.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	protected Writer out;
    
    	/**
    	 * True iff we just began a new line.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	protected boolean newLine = true;
    
    	/**
    	 * Default start of comments
    	 */
    	private static final char COMMENT_START_DEFAULT = '#';
    
    	/**
    	 * Character used to start comments. (Default is '#')
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	protected char commentStart = COMMENT_START_DEFAULT;
    
    	/**
    	 * Line ending default
    	 */
    	private static final String LINE_ENDING_DEFAULT = "\n";
    
    	/**
    	 * Line ending indicating the system line ending should be chosen
    	 */
    	private static final String LINE_ENDING_SYSTEM = null;
    
    	/**
    	 * The line ending, must be one of "\n", "\r", or "\r\n"
    	 *
    	 * @since ostermillerutils 1.06.01
    	 */
    	protected String lineEnding = LINE_ENDING_DEFAULT;
    
    	/**
    	 * Change this printer so that it uses a new delimiter.
    	 *
    	 * @param newDelimiter The new delimiter character to use.
    	 * @throws BadDelimiterException if the character cannot be used as a delimiter.
    	 *
    	 * @since ostermillerutils 1.02.18
    	 */
    	public void changeDelimiter(char newDelimiter) throws BadDelimiterException {
    		if (delimiterChar == newDelimiter) return; // no need to do anything.
    		if (newDelimiter == '\n' || newDelimiter == '\r' ||
    				newDelimiter == delimiterChar || newDelimiter == quoteChar){
    			throw new BadDelimiterException();
    		}
    		delimiterChar = newDelimiter;
    	}
    
    	/**
    	 * Change this printer so that it uses a new character for quoting.
    	 *
    	 * @param newQuote The new character to use for quoting.
    	 * @throws BadQuoteException if the character cannot be used as a quote.
    	 *
    	 * @since ostermillerutils 1.02.18
    	 */
    	public void changeQuote(char newQuote) throws BadQuoteException {
    		if (quoteChar == newQuote) return; // no need to do anything.
    		if (newQuote == '\n' || newQuote == '\r' ||
    				newQuote == delimiterChar || newQuote == quoteChar){
    			throw new BadQuoteException();
    		}
    		quoteChar = newQuote;
    	}
    
    	/**
    	 * Change this printer so that it uses a new line ending.
    	 * <p>
    	 * A line ending must be one of "\n", "\r", or "\r\n".
    	 * <p>
    	 * The default line ending is the system line separator as specified by
    	 * <code>System.getProperty("line.separator")</code>, or "\n" if the system
    	 * line separator is not a legal line ending.
    	 *
    	 * @param lineEnding The new line ending, or null to use the default line ending.
    	 * @throws BadLineEndingException if the line ending is not one of the three legal line endings.
    	 *
    	 * @since ostermillerutils 1.06.01
    	 */
    	public void setLineEnding(String lineEnding) throws BadLineEndingException {
    		boolean setDefault = lineEnding == null;
    		if (setDefault){
    			lineEnding = System.getProperty("line.separator");
    		}
    		if (!"\n".equals(lineEnding) && !"\r".equals(lineEnding) && !"\r\n".equals(lineEnding)){
    			if (setDefault){
    				lineEnding = LINE_ENDING_DEFAULT;
    			} else {
    				throw new BadLineEndingException();
    			}
    		}
    		this.lineEnding = lineEnding;
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.	 Character to byte conversion is done using
    	 * the default character encoding.	Comments will be
    	 * written using the default comment character '#', the delimiter will
    	 * be the comma, the line ending will be the default system line ending,
    	 * the quote character will be double quotes,
    	 * quotes will be used when needed, and auto flushing
    	 * will be enabled.
    	 *
    	 * @param out stream to which to print.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public CSVPrinter(OutputStream out){
    		this(
    			new OutputStreamWriter(out)
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.	Comments will be
    	 * written using the default comment character '#', the delimiter will
    	 * be the comma, the line ending will be the default
    	 * system line ending, the quote character will be double quotes,
    	 * quotes will be used when needed, and auto flushing
    	 * will be enabled.
    	 *
    	 * @param out stream to which to print.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public CSVPrinter(Writer out){
    		this(
    			out,
    			COMMENT_START_DEFAULT
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.	 Character to byte conversion is done using
    	 * the default character encoding.  The delimiter will
    	 * be the comma, the line ending will be the default system
    	 * line ending, the quote character will be double quotes,
    	 * quotes will be used when needed, and auto flushing
    	 * will be enabled.
    	 *
    	 * @param out stream to which to print.
    	 * @param commentStart Character used to start comments.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public CSVPrinter(OutputStream out, char commentStart){
    		this(
    			new OutputStreamWriter(out),
    			commentStart
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.  The delimiter will
    	 * be the comma, the line ending will be the default
    	 * system line ending, the quote character will be double quotes,
    	 * quotes will be used when needed, and auto flushing
    	 * will be enabled.
    	 *
    	 * @param out stream to which to print.
    	 * @param commentStart Character used to start comments.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public CSVPrinter(Writer out, char commentStart){
    		this(
    			out,
    			commentStart,
    			QUOTE_DEFAULT,
    			DELIMITER_DEFAULT
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.	The comment character will be the number sign, the delimiter will
    	 * be the comma, the line ending will be the default
    	 * system line ending, and the quote character will be double quotes.
    	 *
    	 * @param out stream to which to print.
    	 * @param alwaysQuote true if quotes should be used even when not strictly needed.
    	 * @param autoFlush should auto flushing be enabled.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public CSVPrinter(Writer out, boolean alwaysQuote, boolean autoFlush){
    		this(
    			out,
    			COMMENT_START_DEFAULT,
    			QUOTE_DEFAULT,
    			DELIMITER_DEFAULT,
    			alwaysQuote,
    			autoFlush
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.	 The line ending will be the default system line
    	 * ending, quotes will be used when needed, and auto flushing
    	 * will be enabled.
    	 *
    	 * @param out stream to which to print.
    	 * @param commentStart Character used to start comments.
    	 * @param delimiter The new delimiter character to use.
    	 * @param quote The new character to use for quoting.
    	 * @throws BadQuoteException if the character cannot be used as a quote.
    	 * @throws BadDelimiterException if the character cannot be used as a delimiter.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public CSVPrinter(Writer out, char commentStart, char quote, char delimiter) throws BadDelimiterException, BadQuoteException {
    		this(
    			out,
    			commentStart,
    			quote,
    			delimiter,
    			LINE_ENDING_SYSTEM
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.	Quotes will be used when needed, and auto flushing
    	 * will be enabled.
    	 *
    	 * @param out stream to which to print.
    	 * @param commentStart Character used to start comments.
    	 * @param delimiter The new delimiter character to use.
    	 * @param quote The new character to use for quoting.
    	 * @param lineEnding The new line ending, or null to use the default line ending.
    	 * @throws BadQuoteException if the character cannot be used as a quote.
    	 * @throws BadDelimiterException if the character cannot be used as a delimiter.
    	 * @throws BadLineEndingException if the line ending is not one of the three legal line endings.
    	 *
    	 * @since ostermillerutils 1.06.01
    	 */
    	public CSVPrinter(Writer out, char commentStart, char quote, char delimiter, String lineEnding) throws BadDelimiterException, BadQuoteException, BadLineEndingException {
    		this(
    			out,
    			commentStart,
    			quote,
    			delimiter,
    			lineEnding,
    			ALWAYS_QUOTE_DEFAULT,
    			AUTO_FLUSH_DEFAULT
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.  The line ending will be the default system line ending,
    	 *
    	 * @param out stream to which to print.
    	 * @param commentStart Character used to start comments.
    	 * @param delimiter The new delimiter character to use.
    	 * @param quote The new character to use for quoting.
    	 * @param alwaysQuote true if quotes should be used even when not strictly needed.
    	 * @param autoFlush should auto flushing be enabled.
    	 * @throws BadQuoteException if the character cannot be used as a quote.
    	 * @throws BadDelimiterException if the character cannot be used as a delimiter.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public CSVPrinter(Writer out, char commentStart, char quote, char delimiter, boolean alwaysQuote, boolean autoFlush) throws BadDelimiterException, BadQuoteException {
    		this (
    			out,
    			commentStart,
    			quote,
    			delimiter,
    			LINE_ENDING_SYSTEM,
    			alwaysQuote,
    			autoFlush
    		);
    	}
    
    	/**
    	 * Create a printer that will print values to the given
    	 * stream.
    	 *
    	 * @param out stream to which to print.
    	 * @param commentStart Character used to start comments.
    	 * @param delimiter The new delimiter character to use.
    	 * @param lineEnding The new line ending, or null to use the default line ending.
    	 * @param quote The new character to use for quoting.
    	 * @param alwaysQuote true if quotes should be used even when not strictly needed.
    	 * @param autoFlush should auto flushing be enabled.
    	 * @throws BadQuoteException if the character cannot be used as a quote.
    	 * @throws BadDelimiterException if the character cannot be used as a delimiter.
    	 * @throws BadLineEndingException if the line ending is not one of the three legal line endings.
    	 *
    	 * @since ostermillerutils 1.06.01
    	 */
    	public CSVPrinter(Writer out, char commentStart, char quote, char delimiter, String lineEnding, boolean alwaysQuote, boolean autoFlush) throws BadDelimiterException, BadQuoteException, BadLineEndingException {
    		this.out = out;
    		this.commentStart = commentStart;
    		changeQuote(quote);
    		changeDelimiter(delimiter);
    		setLineEnding(lineEnding);
    		setAlwaysQuote(alwaysQuote);
    		setAutoFlush(autoFlush);
    	}
    
    	/**
    	 * Print the string as the last value on the line.	The value
    	 * will be quoted if needed.
    	 * <p>
    	 * This method never throws an I/O exception. The client may inquire as to whether
    	 * any errors have occurred by invoking checkError().  If an I/O Exception is
    	 * desired, the client should use the corresponding writeln method.
    	 *
    	 * @param value value to be outputted.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public void println(String value){
    		try {
    			writeln(value);
    		} catch (IOException iox){
    			error = true;
    		}
    	}
    
    	/**
    	 * Print the string as the last value on the line.	The value
    	 * will be quoted if needed.
    	 *
    	 * @param value value to be outputted.
    	 * @throws IOException if an error occurs while writing.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void writeln(String value) throws IOException {
    		try {
    			write(value);
    			writeln();
    		} catch (IOException iox){
    			error = true;
    			throw iox;
    		}
    	}
    
    	/**
    	 * Output a blank line.
    	 * <p>
    	 * This method never throws an I/O exception. The client may inquire as to whether
    	 * any errors have occurred by invoking checkError().  If an I/O Exception is
    	 * desired, the client should use the corresponding writeln method.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public void println(){
    		try {
    			writeln();
    		} catch (IOException iox){
    			error = true;
    		}
    	}
    
    	/**
    	 * Output a blank line.
    	 *
    	 * @throws IOException if an error occurs while writing.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void writeln() throws IOException {
    		try {
    			out.write(lineEnding);
    			if (autoFlush) flush();
    			newLine = true;
    		} catch (IOException iox){
    			error = true;
    			throw iox;
    		}
    	}
    
    	/**
    	 * Print a single line of comma separated values.
    	 * The values will be quoted if needed.  Quotes and
    	 * and other characters that need it will be escaped.
    	 * <p>
    	 * This method never throws an I/O exception. The client may inquire as to whether
    	 * any errors have occurred by invoking checkError().  If an I/O Exception is
    	 * desired, the client should use the corresponding writeln method.
    	 *
    	 * @param values values to be outputted.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public void println(String[] values){
    		try {
    			writeln(values);
    		} catch (IOException iox){
    			error = true;
    		}
    	}
    
    	/**
    	 * Print a single line of comma separated values.
    	 * The values will be quoted if needed.  Quotes and
    	 * and other characters that need it will be escaped.
    	 *
    	 * @param values values to be outputted.
    	 * @throws IOException if an error occurs while writing.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void writeln(String[] values) throws IOException {
    		try {
    			print(values);
    			writeln();
    		} catch (IOException iox){
    			error = true;
    			throw iox;
    		}
    	}
    
    	/**
    	 * Print a single line of comma separated values.
    	 * The values will be quoted if needed.  Quotes and
    	 * and other characters that need it will be escaped.
    	 * <p>
    	 * This method never throws an I/O exception. The client may inquire as to whether
    	 * any errors have occurred by invoking checkError().  If an I/O Exception is
    	 * desired, the client should use the corresponding writeln method.
    	 *
    	 * @param values values to be outputted.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public void print(String[] values){
    		try {
    			write(values);
    		} catch (IOException iox){
    			error = true;
    		}
    	}
    
    	/**
    	 * Print a single line of comma separated values.
    	 * The values will be quoted if needed.  Quotes and
    	 * and other characters that need it will be escaped.
    	 *
    	 * @param values values to be outputted.
    	 * @throws IOException if an error occurs while writing.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void write(String[] values) throws IOException {
    		try {
    			for (int i=0; i<values.length; i++){
    				write(values[i]);
    			}
    		} catch (IOException iox){
    			error = true;
    			throw iox;
    		}
    	}
    
    	/**
    	 * Print several lines of comma separated values.
    	 * The values will be quoted if needed.  Quotes and
    	 * newLine characters will be escaped.
    	 * <p>
    	 * This method never throws an I/O exception. The client may inquire as to whether
    	 * any errors have occurred by invoking checkError().  If an I/O Exception is
    	 * desired, the client should use the corresponding writeln method.
    	 *
    	 * @param values values to be outputted.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public void println(String[][] values){
    		try {
    			writeln(values);
    		} catch (IOException iox){
    			error = true;
    		}
    	}
    
    	/**
    	 * Print several lines of comma separated values.
    	 * The values will be quoted if needed.  Quotes and
    	 * newLine characters will be escaped.
    	 *
    	 * @param values values to be outputted.
    	 * @throws IOException if an error occurs while writing.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void writeln(String[][] values) throws IOException {
    		try {
    			for (int i=0; i<values.length; i++){
    				writeln(values[i]);
    			}
    			if (values.length == 0){
    				writeln();
    			}
    		} catch (IOException iox){
    			error = true;
    			throw iox;
    		}
    	}
    
    	/**
    	 * Put a comment among the comma separated values.
    	 * Comments will always begin on a new line and occupy a
    	 * least one full line. The character specified to star
    	 * comments and a space will be inserted at the beginning of
    	 * each new line in the comment.  If the comment is null,
    	 * an empty comment is outputted.
    	 * <p>
    	 * This method never throws an I/O exception. The client may inquire as to whether
    	 * any errors have occurred by invoking checkError().  If an I/O Exception is
    	 * desired, the client should use the corresponding writelnComment method.
    	 *
    	 * @param comment the comment to output.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public void printlnComment(String comment){
    		try {
    			writelnComment(comment);
    		} catch (IOException iox){
    			error = true;
    		}
    	}
    
    	/**
    	 * Put a comment among the comma separated values.
    	 * Comments will always begin on a new line and occupy a
    	 * least one full line. The character specified to star
    	 * comments and a space will be inserted at the beginning of
    	 * each new line in the comment.  If the comment is null,
    	 * an empty comment is outputted.
    	 *
    	 * @param comment the comment to output.
    	 * @throws IOException if an error occurs while writing.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void writelnComment(String comment) throws IOException {
    		try {
    			if (comment==null) comment = "";
    			if (!newLine){
    				writeln();
    			}
    			out.write(commentStart);
    			out.write(' ');
    			for (int i=0; i<comment.length(); i++){
    				char c = comment.charAt(i);
    				switch (c){
    					case '\r': {
    						if (i+1 < comment.length() && comment.charAt(i+1) == '\n'){
    							i++;
    						}
    					} //break intentionally excluded.
    					case '\n': {
    						writeln();
    						out.write(commentStart);
    						out.write(' ');
    					} break;
    					default: {
    						out.write(c);
    					} break;
    				}
    			}
    			writeln();
    		} catch (IOException iox){
    			error = true;
    			throw iox;
    		}
    	}
    
    	/**
    	 * Print the string as the next value on the line.	The value
    	 * will be quoted if needed.  If value is null, an empty value is printed.
    	 * <p>
    	 * This method never throws an I/O exception. The client may inquire as to whether
    	 * any errors have occurred by invoking checkError().  If an I/O Exception is
    	 * desired, the client should use the corresponding println method.
    	 *
    	 * @param value value to be outputted.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	public void print(String value){
    		try {
    			write(value);
    		} catch (IOException iox){
    			error = true;
    		}
    	}
    
    	/**
    	 * Print the string as the next value on the line.	The value
    	 * will be quoted if needed.  If value is null, an empty value is printed.
    	 *
    	 * @param value value to be outputted.
    	 * @throws IOException if an error occurs while writing.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void write(String value) throws IOException {
    		try {
    			if (value == null) value = "";
    			boolean quote = false;
    			if (alwaysQuote){
    				quote = true;
    			} else if (value.length() > 0){
    				char c = value.charAt(0);
    				if (newLine && (c<'0' || (c>'9' && c<'A') || (c>'Z' && c<'a') || (c>'z'))){
    					quote = true;
    				}
    				if (c==' ' || c=='\f' || c=='\t'){
    					quote = true;
    				}
    				for (int i=0; i<value.length(); i++){
    					c = value.charAt(i);
    					if (c==quoteChar || c==delimiterChar || c=='\n' || c=='\r'){
    						quote = true;
    					}
    				}
    				if (c==' ' || c=='\f' || c=='\t'){
    					quote = true;
    				}
    			} else if (newLine) {
    				// always quote an empty token that is the first
    				// on the line, as it may be the only thing on the
    				// line.  If it were not quoted in that case,
    				// an empty line has no tokens.
    				quote = true;
    			}
    			if (newLine){
    				newLine = false;
    			} else {
    				out.write(delimiterChar);
    			}
    			if (quote){
    				out.write(escapeAndQuote(value));
    			} else {
    				out.write(value);
    			}
    			if (autoFlush) flush();
    		} catch (IOException iox){
    			error = true;
    			throw iox;
    		}
    	}
    
    	/**
    	 * Enclose the value in quotes and escape the quote
    	 * and comma characters that are inside.
    	 *
    	 * @param value needs to be escaped and quoted
    	 * @return the value, escaped and quoted.
    	 *
    	 * @since ostermillerutils 1.00.00
    	 */
    	private String escapeAndQuote(String value){
    		int count = 2;
    		for (int i=0; i<value.length(); i++){
    			char c = value.charAt(i);
    			switch(c){
    				case '\n': case '\r': case '\\': {
    					count ++;
    				} break;
    				default: {
    					if (c == quoteChar){
    						count++;
    					}
    				} break;
    			}
    		}
    		StringBuffer sb = new StringBuffer(value.length() + count);
    		sb.append(quoteChar);
    		for (int i=0; i<value.length(); i++){
    			char c = value.charAt(i);
    			switch(c){
    				case '\n': {
    					sb.append("\\n");
    				} break;
    				case '\r': {
    					sb.append("\\r");
    				} break;
    				case '\\': {
    					sb.append("\\\\");
    				} break;
    				default: {
    					if (c == quoteChar){
    						sb.append("\\" + quoteChar);
    					} else {
    						sb.append(c);
    					}
    				}
    			}
    		}
    		sb.append(quoteChar);
    		return (sb.toString());
    	}
    
    	/**
    	 * Flush any data written out to underlying streams.
    	 *
    	 * @throws IOException if IO error occurs
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void flush() throws IOException {
    		out.flush();
    	}
    
    	/**
    	 * Close any underlying streams.
    	 *
    	 * @throws IOException if IO error occurs
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void close() throws IOException {
    		out.close();
    	}
    
    	/**
    	 * Flush the stream if it's not closed and check its error state.
    	 * Errors are cumulative; once the stream encounters an error,
    	 * this routine will return true on all successive calls.
    	 *
    	 * @return True if the print stream has encountered an error,
    	 * either on the underlying output stream or during a format conversion.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public boolean checkError(){
    		try {
    			if (error) return true;
    			flush();
    			if (error) return true;
    			if (out instanceof PrintWriter){
    				error = ((PrintWriter)out).checkError();
    			}
    		} catch (IOException iox){
    			error = true;
    		}
    		return error;
    	}
    
    	/**
    	 * Set flushing behavior.  Iff set, a flush command
    	 * will be issued to any underlying stream after each
    	 * print or write command.
    	 *
    	 * @param autoFlush should auto flushing be enabled.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void setAutoFlush(boolean autoFlush){
    		this.autoFlush = autoFlush;
    	}
    
    	/**
    	 * Set whether values printers should always be quoted, or
    	 * whether the printer may, at its discretion, omit quotes
    	 * around the value.
    	 *
    	 * @param alwaysQuote true if quotes should be used even when not strictly needed.
    	 *
    	 * @since ostermillerutils 1.02.26
    	 */
    	public void setAlwaysQuote(boolean alwaysQuote){
    		this.alwaysQuote = alwaysQuote;
    	}
    }