11

I have a ArrayList<Metadata> and i want to know if there is a Java API for working with CSV files which has a write method which accepts a ArrayList<> as parameter similar to LinqToCsv in .Net. As i know OpenCSV is available but the CsvWriter class doesn't accept a collection. My Metadata Class is

public class Metadata{
    private String page;
    private String document;
    private String loan;
    private String type;
}
ArrayList<Metadata> record = new ArrayList<Metadata>();

once i populate the record, i want to write each row into a csv file. Please suggest.

Hack-R
  • 19,705
  • 11
  • 63
  • 110
Maverick
  • 1,289
  • 4
  • 20
  • 38

3 Answers3

14

Surely there'll be a heap of APIs that will do this for you, but why not do it yourself for such a simple case? It will save you a dependency, which is a good thing for any project of any size.

Create a toCsvRow() method in Metadata that joins the strings separated by a comma.

public String toCsvRow() {
    return Stream.of(page, document, loan, type)
            .map(value -> value.replaceAll("\"", "\"\""))
            .map(value -> Stream.of("\"", ",").anyMatch(value::contains) ? "\"" + value + "\"" : value)
            .collect(Collectors.joining(","));
}

Collect the result of this method for every Metadata object separated by a new line.

String recordAsCsv = record.stream()
        .map(Metadata::toCsvRow)
        .collect(Collectors.joining(System.getProperty("line.separator")));

EDIT Should you not be so fortunate as to have Java 8 and the Stream API at your disposal, this would be almost as simple using a traditional List.

public String toCsvRow() {
    String csvRow = "";
    for (String value : Arrays.asList(page, document, loan, type)) {
        String processed = value;
        if (value.contains("\"") || value.contains(",")) {
            processed = "\"" + value.replaceAll("\"", "\"\"") + "\"";
        }
        csvRow += "," + processed;
    }
    return csvRow.substring(1);
}
Henrik
  • 4,104
  • 13
  • 27
  • It creates a [stream](https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html#package.description) of an arbitrary number of objects of the same type. Streams are a new feature of Java 8. – Henrik Jan 31 '16 at 11:28
  • ok, i am bound to Java 7, that's why it was not recognizing Stream.of(). is there any possible way to do this without stream i.e on Java 7. – Maverick Jan 31 '16 at 15:47
  • Sure, mapping and collecting streams is just nicer. See updated answer – you should be able to do the last bit of putting each row on a separated line yourself. – Henrik Jan 31 '16 at 18:31
1

By using CSVWriter, you could convert the ArrayList to an array, and pass that to the writer .

csvWriter.writeNext(record.toArray(new String[record.size()]));
Arnaud
  • 16,319
  • 3
  • 24
  • 39
0

If you have an ArrayList of Objects (Metadata in your case) you would use the BeanToCSV instead of the CSVWriter.

You can look at the BeanToCSVTest in the opencsv source code for examples of how to use it.

realPK
  • 1,850
  • 24
  • 20
Scott Conway
  • 885
  • 7
  • 13
  • Typically, answers should stand on their own. Can you add a small code example class? The linked example is nearly 500 lines. – Stevoisiak Apr 05 '17 at 00:30
  • mmmmkay - How about the testWriteQuotes() test within the BeanToCSVTest which takes the testData arrayList and sends the result to the supplied Writer (for the test case it is a StringWriter so as I can test the result. Sorry I do not mean to come off as snippy or sarcastic but I am ungodly busy and don't have time to write up examples. Most of openCSV has tests that, while admitted as a whole are too much to be used as an example, can be looked at individually as examples. In the future I will try and narrow down to specific tests that best answer the question. – Scott Conway Apr 10 '17 at 00:14