如何将CSV文件转换为List<Map<String,String>>?

3

我有一个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

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

1
你能发布一个带有示例输出的CSV文件吗?我不确定应该发生什么。 - Tunaki
1
你不能那样跳过第一行。你需要列的名称。不要使用流来处理这个。 - Sotirios Delimanolis
那么使用流无法实现吗? - Vivek Kothari
1
您可以通过普通的 br.readLine() 调用来检索标题行,然后通过 br.lines().stream ops 处理剩余行。 - Holger
2个回答

9
以下内容可行。通过直接在BufferedReader上调用readLine并围绕,拆分来检索标题行。然后,读取文件的其余部分:将每行围绕,拆分,并映射到相应标题的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

toMap函数中的i需要显式转换为整型。这个方法对我有效:.collect(toMap((Integer i) -> headers[i], i -> t[i]))) - Vivek Kothari
2
顺便提一下,我仍然建议使用类似Commons CSV的库来读取CSV。 CSV格式支持引用,允许在字段内部包含逗号。 提供的实现将无法正确读取这样的文件。 - Tagir Valeev
@VivekKothari 也许这是您正在使用的IDE的一个错误。答案中给出的代码在Eclipse Mars和javac 1.8.0_51下编译正常。 - Tunaki
我正在使用Eclipse Luna和Java版本“1.8.0_40” Java(TM) SE Runtime Environment(构建1.8.0_40-b25)Java HotSpot(TM) 64-Bit Server VM(构建25.40-b25,混合模式)。但是我遇到了错误。 - Vivek Kothari

1

我知道这是一个有点老的问题,但我遇到了同样的问题,并创建了一个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());
            }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接