akapulko2020
akapulko2020

Reputation: 1139

Looking for a java CSV library that allows reading columns by name

Also, allows handling of long rows in a readable/easy manner, in writing them as well as in reading them.

I've looked into opencsv but it does not refer to elements in row in any sequential fashion, and supercsv does not allow looking into column by name but number only.

Another caveat - for which I need to be able to address columns by name - is that the number of columns is not constant, and only part of the column headers are constant, something like:

Name|Number|Color1|Color2......|Color67|   

where not all colors between 1 and 67 are present in any given CSV file.

Upvotes: 4

Views: 9031

Answers (4)

Ahmed Nabil
Ahmed Nabil

Reputation: 18966

Basically we have multiple options, I will share 2 of them:

Option 1: Using (Apache Commons CSV)

  • mvn dependency:
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-csv</artifactId>
    <version>1.9.0</version>
</dependency>
  • sample CSV reader/parser by name:
CSVFormat csvFormat = CSVFormat.DEFAULT
        .withDelimiter(separator)       // Set custom delimiter
        .withQuote(quoteChar)           // Set custom quote character
        .withFirstRecordAsHeader()      // Treat the first row as the header (after optional skipping)
        .withIgnoreEmptyLines()         // ignore empty lines
        ;

Reader reader = new FileReader(filepath);
CSVParser csvParser = new CSVParser(reader, csvFormat);

List<CSVRecord> records = csvParser.getRecords();
CSVRecord csvRecord1 = records.get(0);
String empolyeeName = csvRecord1.get("EmployeeName"); // reading column by name

Option 2: Using (FastCSV)

<dependency>
    <groupId>de.siegmar</groupId>
    <artifactId>fastcsv</artifactId>
    <version>2.2.1</version>
</dependency>
  • sample CSV reader/parser by name:
BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(filepath));

NamedCsvReader namedCsvReader = NamedCsvReader.builder()
        .fieldSeparator(separator)
        .quoteCharacter(quoteChar)
        .build(bufferedReader);

List<NamedCsvRow> namedCsvRowList = namedCsvReader.stream().collect(Collectors.toList());
NamedCsvRow namedCsvRow1 = namedCsvRowList.get(0);
String empolyeeName = namedCsvRow1.getField("EmployeeName"); // reading column by name

Upvotes: 0

xiaolei yu
xiaolei yu

Reputation: 121

You could use the open source library uniVocity-parsers. With this library, not only you can select columns as you want, but also you can select columns in any sequence.

With the following headers: Name|Number|Color1|Color2......|Color67|

We choose only the columns "Color1", "Color3", and "Color2" from the csv with the following code:

public static void main(String[] args) throws FileNotFoundException {

    // 1st, config the CSV reader
    CsvParserSettings settings = new CsvParserSettings();
    settings.getFormat().setLineSeparator("\n");
    settings.selectFields("Color1", "Color3", "Color2");

    // 2nd, creates a CSV parser with the configs
    CsvParser parser = new CsvParser(settings);

    // 3rd, parses all rows of data in selected columns from the CSV file into a matrix
    List<String[]> resolvedData = parser.parseAll(new FileReader("/examples/example.csv"));

    // 3rd, process the matrix with business logic
    for (String[] row : resolvedData) {
        StringBuilder strBuilder = new StringBuilder();
        for (String col : row) {
            strBuilder.append(col).append("\t");
        }
        System.out.println(strBuilder);
    }
}

And you will get output data for these 3 columns:

red blue gray
blue yellow white

Upvotes: 3

ig0774
ig0774

Reputation: 41237

I can't really speak to opencsv, but if you have a fixed number of fields you might be able to use the JavaBean binding to do something like this.

Super CSV however, definitely supports reading and writing CSV rows by name using CsvBeanReader, CsvDozerBeanReader or CsvMapReader (and their writing equivalents).

If you prefer to keep things simple and use a map (with the column name as key, and the column value as the value) then you could use CsvMapReader. There are examples on reading and writing with CsvMapReader on the Super CSV website.

A reading example:

 ICsvMapReader mapReader = new CsvMapReader(
      new FileReader("foo.csv"), CsvPreference.EXCEL_PREFERENCE);
 try {
  final String[] headers = mapReader.getHeader(true);
  Map<String, String> row;
  while( (row = mapReader.read(headers)) != null) {
    for (String header : headers) {
      System.out.println(header + " is " + row.get(header));
    }
  }
} finally {
  mapReader.close();
}

Writing is quite similar.

Upvotes: 6

andyb
andyb

Reputation: 43823

CsvReader has a get() method to read a column by name. The CsvWriter counterpart cannot write to a named column though, so it might only solve half your problem.

Upvotes: 1

Related Questions