在Java中读取大型CSV文件

在Java中读取大型CSV文件,java,file,buffer,large-files,opencsv,Java,File,Buffer,Large Files,Opencsv,我正在尝试用Java读取一个1000000行的CSV文件。我使用的是OpenCSV库,它可以在一个小于30000行的文件中正常工作。在半秒钟内处理它。但当我试图读取百万行文件时,它永远不会结束 现在我测试了一下,看它什么时候会真正停止,通过使用我自己版本的二进制搜索,我首先尝试读取500k行,然后是250k,依此类推,我发现它很容易读取145k行,时间0.5-0.7秒,而150k甚至没有完成 我已经彻底地搜索了,找到了我在代码中使用的几种解决方案,例如使用BufferedReader,Buffe

我正在尝试用Java读取一个1000000行的CSV文件。我使用的是OpenCSV库,它可以在一个小于30000行的文件中正常工作。在半秒钟内处理它。但当我试图读取百万行文件时,它永远不会结束

现在我测试了一下,看它什么时候会真正停止,通过使用我自己版本的二进制搜索,我首先尝试读取500k行,然后是250k,依此类推,我发现它很容易读取145k行,时间0.5-0.7秒,而150k甚至没有完成

我已经彻底地搜索了,找到了我在代码中使用的几种解决方案,例如使用
BufferedReader
BufferedInputStream
等,但没有一个解决了它。但它仍在145-150k行之间失败


这是我代码的相关部分(用145000替换150000是导致程序在中执行的原因可能问题不在于CSV文件中的行数,而在于它的内容。可能在145k和150k之间的行中有一些数据,这会导致应用程序永远无法完成


如果您从文件中复制前145k行并将其粘贴到新的CSV文件中,直到有1m行为止,您可以对此进行检查。如果您的应用程序可以处理此新文件,那么问题在于数据,而不是行数。

我刚刚查看了OpenCSV实现,我看不到任何东西可以解释这种行为,因为文件它很大,包含很多记录

但OpenCSV能够处理来自网站的多行数据:

使用嵌入的回车符处理带引号的条目(即跨多行的条目)

我认为在您的情况下,有一条记录(第150k条记录的某处)包含错误的引号条目。默认引号字符是
。这可能是一条如下记录:

value,value,"badvalue,value
value,value,value,value
在本例中,OpenCSV ist使用的解析器设置为挂起状态,这意味着要读取的记录将在下一行继续。并且调用
CSVReader.readNext()
尝试读取完成csv记录所需的尽可能多的行。如果没有与放错的引号字符匹配的行,它将不断读取,直到缓冲区耗尽或发生其他错误

要查找记录,您可以像读取文件一样,对记录进行计数并打印出当前计数。这将为您提供最后一条有效记录的编号,然后将像现在一样停止/挂起


然后我将编写一个新程序,只逐行读取文件(不使用CSVParser,只使用普通行)跳过你知道的好的行数。然后从那里打印大约10行,你就有一些数据要分析。

这个问题在p.J.Meisch的文章中讨论过。但是,我找到了一个没有提出的好解决方案

在构建解析器时,请使用
with ignorequotes
方法来解决引号问题

以下示例使用
CsvToBeanBuilder
将CSV文件(位于
filepath
)解析为bean列表。中的值由制表符(“
\t
”)分隔,第一行是标题行,因此被跳过(以免尝试将其解析为bean实例)

listbeans=newcsvtobeanbuilder(新文件阅读器(文件路径))
.带忽略的引用(真)
.带分隔符(“\t”)
.基普林斯(1)
.withType(Bean.class)
.build()
.parse();
本例将保存CSV文件逐行解析为相同的bean类型

listbeans=newarraylist();
Path Path=Path.get(filepath);
字符串[]行;
CSVParser parser=新的CSVParserBuilder()
.带分隔符(“\t”)
.带忽略的引用(真)
.build();
CSVReader reader=新的CSVReaderBuilder(Files.newbuffereder(path))
.withCSVParser(解析器)
.build();
试一试{
reader.readNext();
而((line=reader.readNext())!=null){
Bean=新Bean();
setValue1(第[0]行);
setValue2(第[1]行);
...
setValueN(第[n]行);
}
}捕获(CsvValidationException | IOException e1){
e1.printStackTrace();
}捕获(CsvDataTypeMismatchException | CsvConstraintViolationException e){
e、 printStackTrace();
}

当你说“永不结束”…它实际上在干什么?死锁、内存不足等…使用调试器查看它在干什么,或者在循环中放入一些sysout以查看它是否仍在处理,但速度非常慢??我同意P.J.和Marat的观点,问题在于数据。如果你想继续使用与上述相同的程序,我会考虑r只是以二进制方式缩小数字(145K有效,所以使用147K,然后148K,等等),当它开始花费永远的时间时缩小。然后,您可以查看真实文件中的那一行(以及上面/下面的那一行)以查看数据从何处开始出现错误。
value,value,"badvalue,value
value,value,value,value