CSVFileWriter.java Source code

Java tutorial

Introduction

Here is the source code for CSVFileWriter.java

Source

/*
 *  Copyright (C) 2010 takaji
 *
 *  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 3 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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
//package dakside.csv;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * CSV file writer
 * 
 * @author takaji
 * 
 */
public final class CSVFileWriter {

    protected CSVFormat format;
    protected final BufferedWriter writer;
    int row = 1;

    // <editor-fold defaultstate="collapsed" desc="Constructors">
    public CSVFileWriter(Writer writer) {
        this.writer = new BufferedWriter(writer);
        this.format = new CSVFormat();
    }

    public CSVFileWriter(Writer writer, CSVFormat format) throws FileNotFoundException {
        this.writer = new BufferedWriter(writer);
        this.format = format;
    }

    public CSVFileWriter(BufferedWriter writer) {
        this.writer = writer;
        this.format = new CSVFormat();
    }

    public CSVFileWriter(BufferedWriter writer, CSVFormat format) throws FileNotFoundException {
        this.writer = writer;
        this.format = format;
    }

    public CSVFileWriter(String filename) {
        try {
            this.writer = new BufferedWriter(new FileWriter(new File(filename)));
            this.format = new CSVFormat();
        } catch (IOException ex) {
            Logger.getLogger(CSVFileWriter.class.getName()).log(Level.SEVERE, null, ex);
            throw new CSVException(ex);
        }
    }

    public CSVFileWriter(File f) {
        try {
            this.writer = new BufferedWriter(new FileWriter(f));
            this.format = new CSVFormat();
        } catch (IOException ex) {
            Logger.getLogger(CSVFileWriter.class.getName()).log(Level.SEVERE, null, ex);
            throw new CSVException(ex);
        }
    }

    public CSVFileWriter(OutputStream input) {
        writer = new BufferedWriter(new OutputStreamWriter(input));
        this.format = new CSVFormat();
    }

    public CSVFileWriter(String filename, CSVFormat format) {
        try {
            this.writer = new BufferedWriter(new FileWriter(filename));
            this.format = format;
        } catch (IOException ex) {
            Logger.getLogger(CSVFileWriter.class.getName()).log(Level.SEVERE, null, ex);
            throw new CSVException(ex);
        }
    }

    public CSVFileWriter(File f, CSVFormat format) throws IOException {
        this.writer = new BufferedWriter(new FileWriter(f));
        this.format = format;
    }

    public CSVFileWriter(OutputStream input, CSVFormat format) {
        writer = new BufferedWriter(new OutputStreamWriter(input));
        this.format = format;
    }

    // </editor-fold>
    /**
     * Write a line to CSV<br/>
     *
     * @throws IOException
     */
    public CSVFileWriter writeLine(CSVLine line) throws CSVException {
        if (line == null) {
            return this;
        }

        synchronized (this) {

            // if current line index > 1
            // terminate previous line first
            if (row > 1) {
                carriageReturn();
            }

            if (!line.isEmpty()) {
                // try to write each cell in line
                try {
                    Object[] elements = line.getElements();
                    for (int i = 0; i < elements.length; i++) {
                        // not first element -> write field delimiter
                        if (i > 0) {
                            writer.append(format.getFieldDelimiter());
                        }
                        // write cell content
                        Object cell = elements[i];
                        if (cell != null) {
                            writer.append(escapeString(cell.toString()));
                        } else {
                            writer.append("");
                        }
                        row++;
                    }
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    throw new CSVException(e);
                }
            } else {
                row++;
            }
        }
        return this;
    }

    /**
     * Return carriage
     *
     * @throws IOException
     */
    public CSVFileWriter carriageReturn() throws CSVException {
        try {
            synchronized (writer) {
                writer.append(format.getLineTerminator());
            }
        } catch (IOException e) {
            throw new CSVException("Error while returning carriage.", e);
        }
        return this;
    }

    /**
     * Write a file to underline CSV file
     *
     * @param file
     */
    public void writeFile(CSVFile file) throws CSVException {
        if (file == null) {
            // no need to write
            return;
        }
        CSVLine[] lines = file.getLines();
        synchronized (this) {
            for (int i = 0; i < lines.length; i++) {
                CSVLine line = lines[i];
                writeLine(line);
            }
        }
    }

    /**
     * escape a string with text delimiter if needed
     *
     * @param str
     * @return
     */
    private String escapeString(String str) {

        if (str.indexOf(format.getTextDelimiter()) >= 0 || str.indexOf(format.getLineTerminator()) >= 0
                || str.indexOf(format.getFieldDelimiter()) >= 0) {
            return format.getTextDelimiter() + str.replace("" + format.getTextDelimiter(),
                    "" + format.getTextDelimiter() + format.getTextDelimiter()) + format.getTextDelimiter();
        } else {
            // no need to escape
            return str;
        }
    }

    /**
     * close session
     */
    public void close() {
        try {
            flush();
        } catch (CSVException ex) {
            //do nothing
        }
        try {
            //auto flush
            if (writer != null) {
                writer.close();
            }
        } catch (Exception ex) {
            Logger.getLogger(CSVFileWriter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Flush buffer to underline stream
     */
    public void flush() {
        try {
            synchronized (writer) {
                writer.flush();
            }
        } catch (Exception ex) {
            Logger.getLogger(CSVFileWriter.class.getName()).log(Level.SEVERE, null, ex);
            throw new CSVException("Cannot flush", ex);
        }
    }
}

class CSVFile {

    private ArrayList<CSVLine> lines; //lines inside a CSV file

    /**
     * Default constructor
     */
    public CSVFile() {
        this.lines = new ArrayList<CSVLine>();
    }

    public CSVLine[] getLines() {
        return this.lines.toArray(new CSVLine[0]);
    }

    /**
     * Get line at a specified index
     * @param idx
     * @return
     * @throws IndexOutOfBoundsException
     */
    public CSVLine getLine(int idx) throws IndexOutOfBoundsException {
        return this.lines.get(idx);
    }

    /**
     * Add a new line to current csv
     * @return new line object
     */
    public CSVLine newLine() {
        CSVLine line = new CSVLine();
        this.lines.add(line);
        return line;
    }

    /**
     * get number of line
     * @return number of line
     */
    public int size() {
        return this.lines.size();
    }

    /**
     * discard a line at the specified index
     * @param idx
     */
    public void discard(int idx) {
        if (idx >= 0 && idx < size()) {
            this.lines.remove(idx);
        }
    }

    /**
     * discard empty record
     */
    public void discardEmpty() {
        for (int i = this.lines.size() - 1; i > -1; i--) {
            if (this.lines.get(i) == null || this.lines.get(i).isEmpty()) {
                discard(i);
            }
        }
    }

    /**
     * append a CSV line to file (line is ignored if null)
     * @param line
     */
    void append(CSVLine line) {
        if (line == null) {
            return;
        }
        this.lines.add(line);
    }
}

class CSVException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    public CSVException() {
    }

    public CSVException(Throwable throwable) {
        super(throwable);
    }

    public CSVException(String message) {
        super(message);
    }

    public CSVException(String message, Throwable throwable) {
        super(message, throwable);
    }

}

class CSVLine {

    private ArrayList<Object> elements;

    /**
     * Default constructor
     */
    public CSVLine() {
        this.elements = new ArrayList<Object>();
    }

    /**
     * Get all elements (cells) inside a line
     * @return empty String array if there's no element found inside
     */
    public Object[] getElements() {
        return this.elements.toArray();
    }

    /**
     * Get element at index
     * @param idx
     * @return
     * @throws IndexOutOfBoundsException
     */
    public Object getElementAt(int idx) throws IndexOutOfBoundsException {
        return elements.get(idx);
    }

    /**
     * Set element at
     * @param idx
     * @param value
     * @throws IndexOutOfBoundsException
     */
    public void setElementAt(int idx, Object value) throws IndexOutOfBoundsException {
        elements.set(idx, value);
    }

    /**
     * count elements inside this line
     * @return
     */
    public int size() {
        return elements.size();
    }

    /**
     * Add a new element
     */
    public CSVLine add(Object obj) {
        this.elements.add(obj);
        return this;
    }

    /**
     * if CSV line is empty
     * @return
     */
    public boolean isEmpty() {
        return this.elements.isEmpty();
    }

    /**
     * Remove all elements
     */
    public void clear() {
        this.elements.clear();
    }

    /**
     * Remove element at a specified index
     * @param idx
     * @throws IndexOutOfBoundsException
     */
    public void remove(int idx) throws IndexOutOfBoundsException {
        elements.remove(idx);
    }

    /**
     * Trim down or expand with null cell to a new length
     * @param newLength
     */
    public void setLength(int newLength) {
        if (elements.size() > newLength) {
            //trim down
            while (elements.size() > newLength) {
                elements.remove(elements.size() - 1);
            }
        } else {
            //add more
            while (elements.size() < newLength) {
                add(null);
            }
        }
    }
}

class CSVFormat {

    private String charset;
    private char fieldDelimiter;
    private char textDelimiter;
    private char lineTerminator;
    private char[] ignoreCharacters;

    /**
     * Construct a standard CSV format
     */
    public CSVFormat() {
        this.setCharset("UTF-8");
        this.setFieldDelimiter(',');
        this.setTextDelimiter('"');

        //auto detect line separator
        String s = System.getProperty("line.separator");
        if (s.length() > 0) {
            this.setLineTerminator(s.charAt(0));
            char[] ignoreChars = new char[s.length() - 1];
            for (int i = 1; i < s.length(); i++) {
                ignoreChars[i - 1] = s.charAt(i);
            }
            this.setIgnoreCharacters(ignoreChars);
        } else {
            this.setLineTerminator('\n');
            this.setIgnoreCharacters(new char[] { '\r' });
        }
    }

    /**
     * @param lineTerminator
     *            the lineTerminator to set
     */
    public void setLineTerminator(char lineTerminator) {
        this.lineTerminator = lineTerminator;
    }

    /**
     * @return the lineTerminator
     */
    public char getLineTerminator() {
        return lineTerminator;
    }

    /**
     * @param ignoreCharacters
     *            the ignoreCharacters to set
     */
    public void setIgnoreCharacters(char[] ignoreCharacters) {
        this.ignoreCharacters = ignoreCharacters;
    }

    /**
     * @return the ignoreCharacters
     */
    public char[] getIgnoreCharacters() {
        return ignoreCharacters;
    }

    /**
     * @param charset
     *            the charset to set
     */
    public void setCharset(String charset) {
        this.charset = charset;
    }

    /**
     * @return the charset
     */
    public String getCharset() {
        return charset;
    }

    /**
     * @param fieldDelimiter
     *            the fieldDelimiter to set
     */
    public void setFieldDelimiter(char fieldDelimiter) {
        this.fieldDelimiter = fieldDelimiter;
    }

    /**
     * @return the fieldDelimiter
     */
    public char getFieldDelimiter() {
        return fieldDelimiter;
    }

    /**
     * @param textDelimiter
     *            the textDelimiter to set
     */
    public void setTextDelimiter(char textDelimiter) {
        this.textDelimiter = textDelimiter;
    }

    /**
     * @return the textDelimiter
     */
    public char getTextDelimiter() {
        return textDelimiter;
    }

    /**
     * is ignored characters
     * @param c
     * @return
     */
    public boolean isIgnored(char c) {
        return Arrays.binarySearch(ignoreCharacters, c) >= 0;
    }
}