Why?

Are you looking for a very performant Csv Parser, or even better an easy to use CsvMapper?

sfm-csv provides the most flexible CsvMapper available. It supports Constructor injection, Factory method, Builder Pattern… The new java8 time API, the old joda time API. Inner object mapping, join mapping.

Give it a try.

Getting Started Csv

Maven Central JavaDoc

Setting up the environment

Add the Dependency to your build.

for Maven:

Java 8

<dependency>
    <groupId>org.simpleflatmapper</groupId>
    <artifactId>sfm-csv</artifactId>
    <version>3.12.1</version>
</dependency>

Java 6, 7

<dependency>
    <groupId>org.simpleflatmapper</groupId>
    <artifactId>sfm-csv</artifactId>
    <version>3.12.1</version>
    <classifier>jdk16</classifier>
</dependency>

Java 9

<dependency>
    <groupId>org.simpleflatmapper</groupId>
    <artifactId>sfm-csv</artifactId>
    <version>3.12.1</version>
    <classifier>jdk9ea</classifier>
</dependency>

Reading a csv file

The CsvParser api allows you to read from a File, a Reader or a CharSequence via a CheckedConsumer callback, an Iterator or a Stream of String[]

Source

// Callback
CsvParser
        .forEach(file, row -> System.out.println(Arrays.toString(row)));

// Iterator
try (CloseableIterator<String[]> it = CsvParser.iterator(file)) {
    while(it.hasNext()) {
        System.out.println(Arrays.toString(it.next()));
    }
}

// Stream
try (Stream<String[]> stream = CsvParser.stream(file)) {
    stream.forEach(row -> System.out.println(Arrays.toString(row)));
}

Mapping a csv to an object

You can also ask the row to be mapped to an object. You can then read the csv from a File, a Reader or a CharSequence via a CheckedConsumer callback, an Iterator or a Stream of your type. The mapper will use the header row - the first one - to match against the property of the object. You can also specify the headers manually if there none or if you want to skip them.

Source

// Callback
CsvParser
        .mapTo(MyObject.class)
        .forEach(file, System.out::println);

// Iterator
try (CloseableIterator<MyObject> it =
             CsvParser.mapTo(MyObject.class).iterator(file)) {
    while(it.hasNext()) {
        System.out.println(it.next());
    }
}

// Stream
CsvParser
        .mapTo(MyObject.class)
        .stream(
            file, 
            (s) -> { s.forEach(System.out::println); return null; }
        )

// override headers
CsvParser
        .skip(1)
        .mapTo(MyObject.class)
        .headers("id", "email", "name")
        .forEach(file, System.out::println);

Writing a csv from an object

The CsvWriter allows you to create append object to an Appendable. If no headers are specified it will generate a list of headers from the properties of the object. Though it is better to specify the headers manually.

Source

// better to cache the dsl with the from 
// to avoid recomputing the object metadata
CsvWriter.CsvWriterDSL<MyObject> writerDsl =
    CsvWriter.from(MyObject.class).columns("id" ,"name", "email");

public void writeCsv(Collection<MyObject> objects, File file) 
                                                throws IOException {
    try (FileWriter fileWriter = new FileWriter(file)) {
        CsvWriter<MyObject> writer=
                writerDsl.to(fileWriter);
        objects.forEach(CheckedConsumer.toConsumer(writer::append));
    }
}

writing with headers not matching the property name

if you want to use a header that does not match the name of the property, for example, if you need the email header to be “contact” you will need to add an alias by adding RenameProperty on the column.

// better to cache the dsl with the from 
// to avoid recomputing the object metadata
CsvWriter.CsvWriterDSL<MyObject> writerDsl =
    CsvWriter
        .from(MyObject.class)
        .columns("id" ,"name")
        .column("contact", new RenameProperty("email"));

public void writeCsv(Collection<MyObject> objects, File file) 
                                                throws IOException {
    try (FileWriter fileWriter = new FileWriter(file)) {
        CsvWriter<MyObject> writer=
                writerDsl.to(fileWriter);
        objects.forEach(CheckedConsumer.toConsumer(writer::append));
    }
}