读入大 csv 文件,使用 uniVocity 解析器验证和写出

ily*_*a_i 3 csv validation parsing

我需要解析一个大的 csv 文件 (2gb)。必须验证这些值,必须删除包含“坏”字段的行,并且应该输出仅包含有效行的新文件。

我选择了 uniVocity 解析器库来做到这一点。请帮助我了解这个库是否非常适合该任务以及应该使用什么方法。

  1. 鉴于文件大小,在 uniVocity 中组织 read->validate->write 的最佳方法是什么?一次读取所有行还是使用迭代器样式?解析和验证的行在写入文件之前应该存储在哪里?

  2. Univocity 有没有办法通过索引访问行的值?像 row.getValue(3) 之类的东西?

Jer*_*kes 5

我是这个库的作者,让我试着帮助你:

  1. 首先,不要尝试一次读取所有行,因为您会用大量数据填满您的内存。

  2. 您可以通过索引获取行值。

读取/验证/写入的更快方法是使用RowProcessor具有 aCsvWriter并决定何时写入或跳过一行的 。我认为以下代码会对您有所帮助:

定义输出:

private CsvWriter createCsvWriter(File output, String encoding){
    CsvWriterSettings settings = new CsvWriterSettings();
    //configure the writer ...

    try {
        return new CsvWriter(new OutputStreamWriter(new FileOutputStream(output), encoding), settings);
    } catch (IOException e) {
        throw new IllegalArgumentException("Error writing to " + output.getAbsolutePath(), e);
    }
}
Run Code Online (Sandbox Code Playgroud)

重定向输入

//this creates a row processor for our parser. It validates each row and sends them to the csv writer.
private RowProcessor createRowProcessor(File output, String encoding){
    final CsvWriter writer = createCsvWriter(output, encoding);
    return new AbstractRowProcessor() {

        @Override
        public void rowProcessed(String[] row, ParsingContext context) {
            if (shouldWriteRow(row)) {
                writer.writeRow(row);
            } else {
                //skip row
            }
        }

        private boolean shouldWriteRow(String[] row) {
            //your validation here
            return true;
        }

        @Override
        public void processEnded(ParsingContext context) {
            writer.close();
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

配置解析器:

public void readAndWrite(File input, File output, String encoding) {

    CsvParserSettings settings = new CsvParserSettings();
    //configure the parser here

    //tells the parser to send each row to them custom processor, which will validate and redirect all rows to the CsvWriter
    settings.setRowProcessor(createRowProcessor(output, encoding));

    CsvParser parser = new CsvParser(settings);
    try {
        parser.parse(new InputStreamReader(new FileInputStream(input), encoding));
    } catch (IOException e) {
        throw new IllegalStateException("Unable to open input file " + input.getAbsolutePath(), e);
    }
}
Run Code Online (Sandbox Code Playgroud)

为了获得更好的性能,您还可以将行处理器包装在ConcurrentRowProcessor.

settings.setRowProcessor(new ConcurrentRowProcessor(createRowProcessor(output, encoding)));
Run Code Online (Sandbox Code Playgroud)

这样,行的写入将在单独的线程中执行。

  • 这个怎么样:`private boolean shouldWriteRow(String[] row) { String valueAtIndex10 = row[10]; 返回真;}` (2认同)