我有以下两种读取 csv 文件的实现,有问题的 csv 文件不是那么大(5 兆字节)。
第一个实现是使用 openCSV,第二个是使用 stringTokenizer。
第一个导致内存不足错误,即使我将 java 最大堆内存提高到 1G(Xmx),虽然 StringTokenizer 实现并不健壮,但我别无选择,因为我需要将 csv 文件读入内存。
我不明白为什么 openCSV 版本会消耗这么多内存,因为 csv 文件很小(它有 200k 行,但文件大小只有 5m 左右)。openCSV 阅读器在做什么需要这么多内存?StringTokenizer 版本很快就能轻松完成。
这是 openCSV 实现引发的错误:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at java.util.Arrays.copyOfRange(Arrays.java:3209)
at java.lang.String.<init>(String.java:215)
at java.lang.StringBuilder.toString(StringBuilder.java:430)
at au.com.bytecode.opencsv.CSVParser.parseLine(Unknown Source)
at au.com.bytecode.opencsv.CSVParser.parseLineMulti(Unknown Source)
at au.com.bytecode.opencsv.CSVReader.readNext(Unknown Source)
private List<String[]> parseCSV(File f) {
List<String[]>res=new Vector<String[]>();
CSVReader reader=null;
try{
reader = new CSVReader(new BufferedReader(new FileReader(f)));
String [] nextLine;
while ((nextLine = reader.readNext()) != null) {
for(int i=0;i<nextLine.length;i++)if(nextLine[i]!=null)nextLine[i]=nextLine[i].trim();
res.add(nextLine);
}
}catch(IOException exp){
exp.printStackTrace();
}finally{
if(reader!=null)try {
reader.close();
} catch (IOException ex) {
Logger.getLogger(DataStream2.class.getName()).log(Level.SEVERE, null, ex);
}
}
return res;
}
private List<String[]> parseCSV(File f) {
List<String[]>res=new Vector<String[]>();
BufferedReader br=null;
try{
br = new BufferedReader(new FileReader(f));
String line =null;
while((line=br.readLine())!=null){
StringTokenizer st=new StringTokenizer(",");
String[]cur=new String[st.countTokens()];
for(int i=0;i<cur.length;i++){
cur[i]=st.nextToken().trim();
}
res.add(cur);
}
}catch(IOException exp){
exp.printStackTrace();
}
finally{
if(br!=null)try {
br.close();
} catch (IOException ex) {
Logger.getLogger(DataStream2.class.getName()).log(Level.SEVERE, null, ex);
}
}
return res;
}