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

Java中用Univocity解析6GB大CSV并生成指定格式输出的方法问询

解决方案:用Univocity流式解析并分组合并CSV输出

针对你处理6GB大型CSV并生成特定格式输出的需求,我们可以利用Univocity的流式解析特性,在遍历每行数据时维护当前分组的状态,避免加载整个文件到内存,完美适配大文件场景。

核心思路

你的CSV数据是按以"A"开头的行作为分组头部,后续以"null"开头的行属于当前分组。我们需要:

  • 跟踪当前分组的元数据(分组标识、第四列固定值)
  • 收集分组内所有行的第二列值(用分号分隔)
  • 收集分组内所有行的第三列值(用逗号分隔)
  • 每当遇到新的分组头部时,先输出上一个分组的结果,再初始化新分组;遍历结束后输出最后一个分组

完整实现代码

import com.univocity.parsers.csv.CsvParser;
import com.univocity.parsers.csv.CsvParserSettings;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class CsvGroupParser {
    public static void main(String[] args) {
        CsvParserSettings settings = new CsvParserSettings();
        settings.getFormat().setLineSeparator("\n");
        // 可以根据需要开启更多优化,比如跳过空行等
        settings.setSkipEmptyLines(true);

        CsvParser parser = new CsvParser(settings);
        File f = new File("test.csv");

        // 维护当前分组的状态
        String currentGroupId = null;
        String currentGroupLastValue = null;
        List<String> column2Values = new ArrayList<>();
        List<String> column3Values = new ArrayList<>();

        try {
            parser.beginParsing(f, "UTF-8");
            String[] row;
            while ((row = parser.parseNext()) != null) {
                // 处理分组头部行(以"A"开头)
                if ("A".equals(row[0])) {
                    // 如果已有未输出的分组,先输出
                    if (currentGroupId != null) {
                        printGroup(currentGroupId, column2Values, column3Values, currentGroupLastValue);
                    }
                    // 初始化新分组
                    currentGroupId = row[0];
                    currentGroupLastValue = row[3];
                    column2Values.clear();
                    column3Values.clear();
                    // 把当前头部行的第二、第三列加入集合
                    column2Values.add(row[1]);
                    column3Values.add(row[2]);
                } else if ("null".equals(row[0])) {
                    // 处理分组内的行,收集第二、第三列
                    column2Values.add(row[1]);
                    column3Values.add(row[2]);
                }
            }
            // 遍历结束后,输出最后一个分组
            if (currentGroupId != null) {
                printGroup(currentGroupId, column2Values, column3Values, currentGroupLastValue);
            }
        } finally {
            parser.stopParsing(); // 确保关闭解析器,释放资源
        }
    }

    // 格式化并输出单个分组的结果
    private static void printGroup(String groupId, List<String> col2, List<String> col3, String lastVal) {
        // 用分号拼接第二列集合
        String col2Str = "[" + String.join(";", col2) + "]";
        // 用逗号拼接第三列集合
        String col3Str = "[" + String.join(",", col3) + "]";
        // 按期望格式输出
        System.out.printf("%s,%s,%s,%s%n", groupId, col2Str, col3Str, lastVal);
    }
}

代码说明

  1. 流式解析:Univocity的parseNext()方法逐行读取数据,不会加载整个大文件到内存,适合6GB级别的文件处理。
  2. 分组状态管理:用变量跟踪当前分组的ID和第四列固定值,用List收集分组内的第二、第三列数据,每个分组处理完成后就清空列表,内存占用极低。
  3. 格式化输出:用String.join()替代手动replaceAll(),更简洁高效,避免正则表达式的性能损耗。
  4. 资源释放:在finally块中调用stopParsing(),确保解析器资源被正确释放。

测试结果

针对你提供的test.csv,运行代码后会输出:

A,[10;11;30;44;16],[2,A1,A23,A34,A67],3
A,[20;41;60;74;86],[5,A100,A56,A34,A56],6

完全符合你的期望输出。

额外优化建议

  • 如果CSV中可能存在其他非"A"非"null"开头的行,可以添加逻辑跳过或处理这些行。
  • 可以开启Univocity的并行解析(settings.setNumberOfThreads(...))进一步提升大文件的解析速度,但需要注意线程安全(不过这里每个分组是顺序处理的,并行解析主要是加速行读取)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:36:53