如何通过CSVParser处理大型文件?

15

我有一个大的.csv文件(大约300MB),从远程主机读取并解析成目标文件,但我不需要将所有行都复制到目标文件中。在复制时,我需要从源中读取每一行,如果通过某些谓词,就将该行添加到目标文件中。

我认为Apache CSV(apache.commons.csv)只能解析整个文件。

CSVFormat csvFileFormat = CSVFormat.EXCEL.withHeader();
CSVParser csvFileParser = new CSVParser("filePath", csvFileFormat);
List<CSVRecord> csvRecords = csvFileParser.getRecords();

所以我不能使用BufferedReader。根据我的代码,每行应该创建一个new CSVParser()实例,这看起来效率低下。

在上述情况下,我如何解析单个行(表的已知标题)?

2个回答

23
无论你做什么,你的文件中所有的数据都会传输到本地机器上,因为你的系统需要解析它来确定其有效性。无论是通过解析器读取文件(这样你可以解析每一行),还是只是为了解析目的将整个文件复制过来,它都会全部传输到本地。你需要将数据获取到本地,然后删除多余的部分。
调用csvFileParser.getRecords()已经是一场失败的战斗,因为文档解释说该方法会将文件的每一行加载到内存中。为了在保留活动内存的同时解析记录,你应该迭代每个记录;文档暗示以下代码一次将一条记录加载到内存中:
CSVParser csvFileParser = CSVParser.parse(new File("filePath"), StandardCharsets.UTF_8, csvFileFormat);

for (CSVRecord csvRecord : csvFileParser) {
     ... // qualify the csvRecord; output qualified row to new file and flush as needed.
}

既然您已经解释了"filePath"不是本地的,上述解决方案容易因连接问题而失败。为了消除连接问题,我建议您将整个远程文件复制到本地,通过比较校验和确保文件被正确复制,解析本地副本以创建目标文件,然后在完成后删除本地副本。


7
这是一个晚一些的回复,但您可以使用BufferedReader与CSVParser一起使用:
try (BufferedReader reader = new BufferedReader(new FileReader(fileName), 1048576 * 10)) {
    Iterable<CSVRecord> records = CSVFormat.RFC4180.parse(reader);
    for (CSVRecord line: records) {
        // Process each line here
    }
catch (...) { // handle exceptions from your bufferedreader here

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接