java - 使用 Java 8 读取巨大的 csv 文件并转换为 JSON

标签 java java-8 stream

我正在尝试读取包含许多列的 csv 文件。第一行始终是 csv 文件的标题。我想将 csv 数据转换为 JSON。我可以将它作为字符串读取并转换为 JSON,但我无法为其分配 header 。

例如输入的 csv 看起来像:

first_name,last_name
A,A1
B,B1
C,C1

Stream<String> stream = Files.lines(Paths.get("sample.csv"))
List<String[]> readall = stream.map(l -> l.split(",")).collect(Collectors.toList()); 

List<String> test1 = readall.stream().skip(0).map(row -> row[1]).collect(Collectors.toList());

并且使用 com.fasterxml.jackson.databind.ObjectMapper 的 WriteValueAsString 仅创建没有 header 的 JSON。

我希望输出格式如下

{
[{"first_name":"A","last_name":"A1"},{"first_name":"B"....

如何在 Java 中使用流来准备这种 JSON 格式?

请帮忙。

最佳答案

我会分两步解决这个问题:首先,阅读标题,然后阅读其余的行:

static String[] headers(String path) throws IOException {

    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine().split(",");
    }
}

现在,您可以按如下方式使用上述方法:

String path = "sample.csv";

// Read headers
String[] headers = headers(path);

List<Map<String, String>> result = null;

// Read data
try (Stream<String> stream = Files.lines(Paths.get(path))) {
    result = stream
        .skip(1) // skip headers
        .map(line -> line.split(","))
        .map(data -> {
            Map<String, String> map = new HashMap<>();
            for (int i = 0; i < data.length; i++) {
               map.put(headers[i], data[i]);
            }
            return map;
        })
        .collect(Collectors.toList());
}

您可以在第二个 map 操作中更改 for 循环:

try (Stream<String> stream = Files.lines(Paths.get(path))) {
    result = stream
        .skip(1) // skip headers
        .map(line -> line.split(","))
        .map(data -> IntStream.range(0, data.length)
            .boxed()
            .collect(Collectors.toMap(i -> headers[i], i -> data[i])))
        .collect(Collectors.toList());
}

编辑:如果您想对从每一行读取的 map 执行操作而不是收集到列表,您可以按如下方式执行:

try (Stream<String> stream = Files.lines(Paths.get(path))) {
    stream
        .skip(1) // skip headers
        .map(line -> line.split(","))
        .map(data -> IntStream.range(0, data.length)
            .boxed()
            .collect(Collectors.toMap(i -> headers[i], i -> data[i])))
        .forEach(System.out::println);
}

(这里的 Action 是打印每张 map )。

这个版本可以改进,即它对 int 的流进行装箱,然后再次对每个 int 进行拆箱,以将其用作 headers< 的索引data 数组。此外,可以通过将每个映射的创建提取到私有(private)方法来提高可读性。

注意:也许读取文件两次不是性能方面的最佳方法,但代码简单且富有表现力。除此之外,null 处理、数据转换(即数字或日期等)和边界情况(即没有标题、没有数据行或数据数组的不同长度等)被保留为给读者的练习 ;)

关于java - 使用 Java 8 读取巨大的 csv 文件并转换为 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52419504/

相关文章:

java - 集群中的 Tomcat TLS session 恢复

java - 将文件从一台主机传输到另一台主机并检查其完整性

C#:实现 NetworkStream.Peek?

c++ - 从输入流中读取具有跳过 block 能力的行

java - 从其他类访问 cplex java 变量

java - ejb 客户端的 POM 配置抛出异常

java - 如果哈希码等于实现不正确,我的对象创建会失败吗?

Java 8 方法引用多个不同的构造函数

java - 在spring xml中设置注解属性

Java 多线程 - 有没有办法同步/锁定映射中的特定值以进行读取和写入?