我想读取包含数百万行的csv文件,并使用我的决策树算法的属性。我的代码如下:
String csvFile = "myfile.csv";
List<String[]> rowList = new ArrayList();
String line = "";
String cvsSplitBy = ",";
String encoding = "UTF-8";
BufferedReader br2 = null;
try {
int counterRow = 0;
br2 = new BufferedReader(new InputStreamReader(new FileInputStream(csvFile), encoding));
while ((line = br2.readLine()) != null) {
line=line.replaceAll(",,", ",NA,");
String[] object = line.split(cvsSplitBy);
rowList.add(object);
counterRow++;
}
System.out.println("counterRow is: "+counterRow);
for(int i=1;i<rowList.size();i++){
try{
//this method includes many if elses only.
ImplementDecisionTreeRulesFor2012(rowList.get(i)[0],rowList.get(i)[1],rowList.get(i)[2],rowList.get(i)[3],rowList.get(i)[4],rowList.get(i)[5],rowList.get(i)[6]);
}
catch(Exception ex){
System.out.printlnt("Exception occurred");
}
}
}
catch(Exception ex){
System.out.println("fix"+ex);
}
当csv文件的大小不大时工作正常。但是,确实很大。因此我需要另一种方法来更快地读取csv。有什么建议吗?感谢,谢谢。
答案 0 :(得分:9)
在这个片段中,我看到两个问题会让你大大减慢速度:
while ((line = br2.readLine()) != null) {
line=line.replaceAll(",,", ",NA,");
String[] object = line.split(cvsSplitBy);
rowList.add(object);
counterRow++;
}
首先,rowList以默认容量开始,并且必须多次增加,总是导致旧的底层数组的副本为新的。
然而,更糟糕的是,数据过度爆炸成String []对象。只有在为该行调用ImplementDecisionTreeRulesFor2012 时才需要列/单元格 - 在读取该文件并处理所有其他行时并非所有时间。将分组(或更好的内容,如注释所示)移动到第二行。(创建很多对象很糟糕,即使你能负担得起内存。)
也许最好在阅读“百万”时调用ImplementDecisionTreeRulesFor2012?它会完全避免使用rowList ArrayList。
<强>后来强> 推迟拆分减少了1000万行的执行时间 从1m8.262s(当程序用完堆空间时)到13.067s。
如果您在调用Implp ... 2012之前没有被强制阅读所有行,则时间会减少到4.902秒。
最后编写分割并手动替换:
String[] object = new String[7];
//...read...
String x = line + ",";
int iPos = 0;
int iStr = 0;
int iNext = -1;
while( (iNext = x.indexOf( ',', iPos )) != -1 && iStr < 7 ){
if( iNext == iPos ){
object[iStr++] = "NA";
} else {
object[iStr++] = x.substring( iPos, iNext );
}
iPos = iNext + 1;
}
// add more "NA" if rows can have less than 7 cells
将时间缩短到1.983秒。这比原始代码快30倍左右,原始代码无论如何都会遇到OutOfMemory。
答案 1 :(得分:5)
只需使用uniVocity-parsers'CSV解析器,而不是尝试构建自定义解析器。您的实施可能不会快速或灵活,无法处理所有极端情况。
它具有极高的内存效率,您可以在不到一秒的时间内解析一百万行。 This link对许多java CSV库进行了性能比较,并且将univocity-parsers放在首位。
以下是如何使用它的简单示例:
CsvParserSettings settings = new CsvParserSettings(); // you'll find many options here, check the tutorial.
CsvParser parser = new CsvParser(settings);
// parses all rows in one go (you should probably use a RowProcessor or iterate row by row if there are many rows)
List<String[]> allRows = parser.parseAll(new File("/path/to/your.csv"));
但是,它将所有内容加载到内存中。要流式传输所有行,您可以执行以下操作:
String[] row;
parser.beginParsing(csvFile)
while ((row = parser.parseNext()) != null) {
//process row here.
}
更快的方法是使用RowProcessor,它还提供了更大的灵活性:
settings.setRowProcessor(myChosenRowProcessor);
CsvParser parser = new CsvParser(settings);
parser.parse(csvFile);
最后,它内置routines使用解析器执行一些常见任务(迭代java bean,转储ResultSet
等)
这应涵盖基础知识,查看文档以找到适合您案例的最佳方法。
披露:我是这个图书馆的作者。它是开源和免费的(Apache V2.0许可证)。
答案 2 :(得分:1)
除了上述的不公平之外,还值得检查
其中3个将作为评论时间最快的csv解析器。
很有可能写你自己的解析器会变慢而且错误。
答案 3 :(得分:0)
如果您的目标是对象(即数据绑定),那么我已经编写了一个高性能的sesseltjonna-csv库,您可能会觉得很有趣。与SimpleFlatMapper和uniVocity here进行基准比较。