I have a CsvSchema
and CsvMapper
set up to read CSV
files with column names in the first line.
I need to be able to do some work on the data, alter specific fields, and then write the data back out while preserving the column order.
I'm presuming that the CsvMapper
has an internal schema that it creates from the first line, since the map has all the correct key-value
pairs.
So, is there any way to use the writer
functions of CsvMapper
that would use that schema to order the data for output?
CsvSchema schema = CsvSchema.emptySchema().withHeader();
CsvMapper mapper = new CsvMapper();
MappingIterator<Map<String, String>> it = this.mapper.readerFor(Map.class)
.with(this.schema)
.readValues(stream);
Right now, i'm getting a CsvMappingException
for "Unrecognized column" on the first column of data, so it looks like it's not using the schema.
You can build SequenceWriter
using schema from first row you read from input file. Jackson
uses LinkedHashMap behind, so, order is kept. Assume your CSV
input contains:
C1,name,type
I1,John,T1
I2,Adam,T2
You can read, update and write to console like on below example:
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.SequenceWriter;
import com.fasterxml.jackson.dataformat.csv.CsvMapper;
import com.fasterxml.jackson.dataformat.csv.CsvSchema;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class CsvApp {
private CsvMapper csvMapper = new CsvMapper();
private void handle() throws Exception {
File csvFile = new File("./resource/test.csv").getAbsoluteFile();
CsvSchema schema = CsvSchema.emptySchema().withHeader();
MappingIterator<Map<String, String>> iterator = csvMapper.readerFor(Map.class).with(schema).readValues(csvFile);
SequenceWriter writer = null;
while (iterator.hasNext()) {
final Map<String, String> row = iterator.next();
if (writer == null) {
writer = createWriter(row).writeValues(System.out);
}
// do something ...
for (Map.Entry<String, String> item : row.entrySet()) {
row.replace(item.getKey(), item.getValue() + "U");
}
// write back
writer.write(row);
}
close(writer);
}
private ObjectWriter createWriter(Map<String, String> row) {
CsvSchema.Builder writeSchema = new CsvSchema.Builder();
writeSchema.setUseHeader(true);
row.keySet().forEach(writeSchema::addColumn);
return csvMapper.writerFor(Map.class).with(writeSchema.build());
}
private void close(Closeable closeable) throws IOException {
if (closeable != null) {
closeable.close();
}
}
public static void main(String[] args) throws Exception {
new CsvApp().handle();
}
}
Above code prints:
C1,name,type
I1U,JohnU,T1U
I2U,AdamU,T2U
See also: