如何提取一个非常大的csv文件,转换它,然后使用Java将其加载到另一个文件中?

时间:2018-03-09 12:36:51

标签: java csv out-of-memory etl heap-memory

我有一个传统的文件系统。 数据文件大小为4 GB,看起来像

ID,姓名,角色,部门

1,Patrick,2,3,

2,伊曼纽尔,1,5,

3,Mike,1,5,

我必须将文件转换为:

ID,姓名,角色,部门

1,帕特里克,操作员,研磨

2,伊曼纽尔,助理,人力资源

3,迈克,助理,人力资源

以上数据需要保存到另一个文件中。

避免OutOfMemory异常的最佳方法是什么?

我知道我需要使用像Scanner这样的东西来读取文件,但是如何将中间输出(转换后的数据)存储在类似Map的对象中,这会通过累加每行数据而大大增加?

2 个答案:

答案 0 :(得分:0)

如果您确实需要使用Java,请尝试将其加载到H2数据库中:

CREATE TABLE TEST AS SELECT * FROM CSVREAD('test.csv');

然后,您可以使用SQL转换表并将其写入另一个CSV:

CALL CSVWRITE('test2.csv', 'SELECT * FROM TEST2');

更多信息:http://www.h2database.com/html/tutorial.html#csv

答案 1 :(得分:0)

使用正确(快速)的CSV解析器。使用univocity-parsers整个过程应该需要几秒钟。

首先创建一个RowProcessor,它将接收从输入解析的每一行,转换它并将结果写入给定的输出。

public RowProcessor createProcessor(final File output){
    CsvWriterSettings outputSettings = new CsvWriterSettings();
    //configure the CSV writer - format and other settings.

    //create a writer for the output you want with the given settings. 
    final CsvWriter writer = new CsvWriter(output, "UTF-8", outputSettings);        

    return new com.univocity.parsers.common.processor.RowProcessor(){
        private Map<String, String> roleMap;
        private Map<String, String> deptMap;

        @Override
        public void processStarted(ParsingContext context) {
            roleMap = buildMapOfRoles();
            deptMap = buildMapOfDepartments();
        }

        @Override
        public void rowProcessed(String[] row, ParsingContext context) {
            row[2] = roleMap.get(row[2]);
            row[3] = deptMap.get(row[3]);

            writer.writeRow(row);
        }

        @Override
        public void processEnded(ParsingContext context) {
            writer.close();
        }
    };
}

然后运行解析器:

String encoding = "UTF-8";
File input = new File("/path/to/input.csv");
File output = new File("/path/to/output.csv");

RowProcessor processor = createProcessor(output, encoding);
CsvParserSettings parserSettings = new CsvParserSettings();
parserSettings.setProcessor(processor);
//configure the parser settings as needed.

//then run the parser. It will submit all rows to the processor created above.
new CsvParser(parserSettings).parse(input, encoding);

所有行都将提交给您的processor并将转换后的行直接写入输出

以下是我buildMapOfRolesbuildMapOfDepartments的精彩实现:

private Map<String, String> buildMapOfRoles(){
    Map<String,String> out = new HashMap<>();
    out.put("2", "Operator");
    out.put("1", "Assistant");
    return out;
}

private Map<String, String> buildMapOfDepartments(){
    Map<String,String> out = new HashMap<>();
    out.put("3", "Grinding");
    out.put("5", "HR");
    return out;
}

这将产生您期望的确切输出。希望这有帮助

免责声明:我是这个图书馆的作者。它的开源和免费(Apache 2.0许可证)