如何将CSV文件转换为List <map <string,string>&gt;

时间:2015-10-13 15:50:16

标签: java java-8 java-stream

我有一个CSV文件,第一行有一个标题。我想将其转换为List<Map<String, String>>,其中列表中的每个Map<String, String>代表文件中的记录。地图的关键是标题,值是字段的实际值。 到目前为止我所拥有的:

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);

我可以在recordStream执行哪些进一步操作,以便将其转换为List<Map<String, String>>

示例CSV文件是:

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

最后,需要将所有这些地图收集到列表中。

2 个答案:

答案 0 :(得分:6)

以下内容有效。通过直接在readLine上调用BufferedReader并在,周围进行拆分来检索标题行。然后,读取文件的其余部分:每行分为,并映射到带有相应标题的Map

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);
};

这里非常重要的一点是BufferedReader.lines()在调用时不会返回新的Stream:我们读取标题后不得跳过1行,因为读者已经进入了下一行。

作为旁注,我使用了try-with-resources构造,以便BufferedReader可以正常关闭。

答案 1 :(得分:0)

我知道这是一个老问题,但我遇到了同样的问题,并创建了 Commons CSV 提到的 Tagir Valeev 解决方案的快速示例:

            Reader in = new FileReader("path/to/file.csv");
            Iterable<CSVRecord> records = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in);

            List<Map> listOfMaps = new ArrayList<>();
            for (CSVRecord record : records) {
                listOfMaps.add(record.toMap());
            }