I have a CSV file which has a header in the first line. I want to convert it to List<Map<String, String>>
, where each Map<String, String>
in the list represents a record in the file. The key of the map is the header and the value is the actual value of the field.
What I have so far:
BufferedReader br = <handle to file>; // Get the headers to build the map. String[] headers = br.lines().limit(1).collect(Collectors.toArray(size -> new String[size])); Stream<String> recordStream = br.lines().skip(1);
What further operations can I perform on recordStream
so that I can transform it to List<Map<String, String>>
?
Sample CSV file is:
header1,header2,header3 ---- Header line field11,field12,field13 ----> need to transform to Map where entry would be like header1:field11 header2:field12 and so on. field21,field22,field23 field31,field32,field33
Finally all these Maps need to be collected to a List.
Advertisement
Answer
The following will work. The header line is retrieved by calling readLine
directly on the BufferedReader
and by splitting around ,
. Then, the rest of the file is read: each line is split around ,
and mapped to a Map
with the corresponding header.
try (BufferedReader br = new BufferedReader(...)) { String[] headers = br.readLine().split(","); List<Map<String, String>> records = br.lines().map(s -> s.split(",")) .map(t -> IntStream.range(0, t.length) .boxed() .collect(toMap(i -> headers[i], i -> t[i]))) .collect(toList()); System.out.println(headers); System.out.println(records); };
A very important note here is that BufferedReader.lines()
does not return a fresh Stream
when it is called: we must not skip 1 line after we read the header since the reader will already have advanced to the next line.
As a side note, I used a try-with-resources
construct so that the BufferedReader
can be properly closed.