You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环中将多个JSON字符串转为CSV的Java实现方案咨询

循环处理大JSON转CSV(单JSON 50MB+数百万行)的实现方案

针对你需要在循环中逐个处理大体积JSON、生成CSV且仅保留一行表头的场景,以下是两种高效可行的实现方案,均避免了加载巨型JSON数组的内存问题:

一、基础Java + Jackson(流式解析防OOM)

单个JSON达50MB时,直接将其转为对象会占用大量内存,因此采用Jackson的流式解析逐Token提取字段,配合BufferedWriter实现高效写入。

代码示例

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class JsonToCsvBasic {
    private static final String CSV_PATH = "output.csv";
    // 定义JSON字段与CSV表头的映射(支持大小写转换)
    private static final Map<String, String> FIELD_MAP = new HashMap<>();
    static {
        FIELD_MAP.put("name", "name");
        FIELD_MAP.put("Age", "age");
        // 可扩展添加其他需要的字段
    }

    public static void main(String[] args) {
        Iterable<MyBusinessObj> businessObjs = getBusinessObjects();

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(CSV_PATH, StandardCharsets.UTF_8));
             JsonFactory jsonFactory = new JsonFactory()) {

            boolean isFirstRow = true;

            for (MyBusinessObj obj : businessObjs) {
                String json = convertBOToJson(obj);
                Map<String, String> fieldValues = new HashMap<>();

                // 流式解析JSON,仅提取目标字段
                try (JsonParser parser = jsonFactory.createParser(json)) {
                    JsonToken token;
                    String currentField = null;
                    while ((token = parser.nextToken()) != null) {
                        if (token == JsonToken.FIELD_NAME) {
                            currentField = parser.getCurrentName();
                        } else if (token == JsonToken.VALUE_STRING && currentField != null && FIELD_MAP.containsKey(currentField)) {
                            fieldValues.put(FIELD_MAP.get(currentField), parser.getValueAsString());
                            currentField = null; // 重置避免重复匹配
                        }
                    }
                }

                // 写入表头(仅第一次循环执行)
                if (isFirstRow) {
                    String header = String.join(",", FIELD_MAP.values());
                    writer.write(header);
                    writer.newLine();
                    isFirstRow = false;
                }

                // 组装并写入数据行,自动处理引号转义
                String row = String.join(",", FIELD_MAP.values().stream()
                        .map(fieldValues::get)
                        .map(val -> val == null ? "" : "\"" + val.replace("\"", "\"\"") + "\"")
                        .toArray(String[]::new));
                writer.write(row);
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 模拟业务对象获取方法
    private static Iterable<MyBusinessObj> getBusinessObjects() {
        // 返回你的业务对象集合
        return null;
    }

    // 模拟业务对象转JSON方法
    private static String convertBOToJson(MyBusinessObj obj) {
        // 返回转换后的JSON字符串
        return null;
    }
}

二、OpenCSV + Jackson 实现

OpenCSV封装了CSV写入的细节(如分隔符、特殊字符转义),代码更简洁,搭配Jackson流式解析同样能避免内存溢出。

代码示例

import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.opencsv.CSVWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class JsonToCsvOpenCsv {
    private static final String CSV_PATH = "output.csv";
    private static final Map<String, String> FIELD_MAP = new HashMap<>();
    static {
        FIELD_MAP.put("name", "name");
        FIELD_MAP.put("Age", "age");
        // 扩展其他字段映射
    }

    public static void main(String[] args) {
        Iterable<MyBusinessObj> businessObjs = getBusinessObjects();
        String[] csvHeaders = FIELD_MAP.values().toArray(new String[0]);

        try (CSVWriter writer = new CSVWriter(new FileWriter(CSV_PATH, StandardCharsets.UTF_8));
             JsonFactory jsonFactory = new JsonFactory()) {

            boolean isFirstRow = true;

            for (MyBusinessObj obj : businessObjs) {
                String json = convertBOToJson(obj);
                Map<String, String> fieldValues = new HashMap<>();

                // 流式解析JSON
                try (JsonParser parser = jsonFactory.createParser(json)) {
                    JsonToken token;
                    String currentField = null;
                    while ((token = parser.nextToken()) != null) {
                        if (token == JsonToken.FIELD_NAME) {
                            currentField = parser.getCurrentName();
                        } else if (token == JsonToken.VALUE_STRING && currentField != null && FIELD_MAP.containsKey(currentField)) {
                            fieldValues.put(FIELD_MAP.get(currentField), parser.getValueAsString());
                            currentField = null;
                        }
                    }
                }

                // 写入表头
                if (isFirstRow) {
                    writer.writeNext(csvHeaders);
                    isFirstRow = false;
                }

                // 组装数据行并写入
                String[] row = new String[csvHeaders.length];
                for (int i = 0; i < csvHeaders.length; i++) {
                    row[i] = fieldValues.getOrDefault(csvHeaders[i], "");
                }
                writer.writeNext(row);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 模拟方法
    private static Iterable<MyBusinessObj> getBusinessObjects() {
        return null;
    }

    private static String convertBOToJson(MyBusinessObj obj) {
        return null;
    }
}

核心优化点

  1. 流式解析:Jackson的JsonParser逐Token解析JSON,无需加载全量50MB数据到内存,彻底避免OOM。
  2. 资源自动管理:使用try-with-resources自动关闭流,防止资源泄漏。
  3. 性能缓冲:BufferedWriter和OpenCSV的CSVWriter均内置缓冲,适配数百万行的高吞吐量写入。
  4. 字段映射:通过FIELD_MAP统一管理JSON键与CSV表头的对应关系,便于后续扩展维护。

内容的提问来源于stack exchange,提问作者Nila

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 23:50:34