我有一个大的.csv
文件(大约300 MB),它从远程主机读取,并解析为目标文件,但我不需要将所有行复制到目标文件。复制时,我需要从源读取每一行,如果它传递了一些谓词,则将该行添加到目标文件中。
我认为Apache CSV(apache.commons.csv
)只能解析整个文件
CSVFormat csvFileFormat = CSVFormat.EXCEL.withHeader();
CSVParser csvFileParser = new CSVParser("filePath", csvFileFormat);
List<CSVRecord> csvRecords = csvFileParser.getRecords();
因此我无法使用BufferedReader
。根据我的代码,应为每一行创建一个new CSVParser()
实例,这看起来效率很低。
如何在上面的案例中解析单行(带有已知的表头)?
答案 0 :(得分:12)
无论您做什么,您文件中的所有数据都将转到本地计算机,因为您的系统需要解析它以确定其有效性。无论文件是通过解析器读取的文件到达(因此您可以解析每一行),还是只是复制整个文件以进行解析,它们都会转到本地。您需要获取本地数据,然后修剪多余的数据。
调用csvFileParser.getRecords()
已经失败了,因为the documentation解释说该方法会将文件的每一行加载到内存中。要在保留活动内存的同时解析记录,您应该迭代每条记录;文档意味着以下代码一次将一条记录加载到内存中:
CSVParser csvFileParser = CSVParser.parse(new File("filePath"), csvFileFormat);
for (CSVRecord csvRecord : csvFileParser) {
... // qualify the csvRecord; output qualified row to new file and flush as needed.
}
由于您解释"filePath"
不是本地的,因此上述解决方案很容易因连接问题而失败。为了消除连接问题,我建议您将整个远程文件复制到本地,确保通过比较校验和来准确复制文件,解析本地副本以创建目标文件,然后在完成后删除本地副本。
答案 1 :(得分:2)
这是一个迟到的回复,但您可以使用CSV {{}的BufferedReader
:
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