1

我有以下两种读取 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;
}
4

3 回答 3

0

也许不太可能,但我猜您的输入数据可能会触发 opencsv 库中的错误,可能会导致它陷入循环。

opencsv 的下载提供了源代码和库,因此您应该能够自己调试代码。

由于堆栈跟踪没有显示 opencsv 代码的行号,我猜您需要更改构建脚本中的 javac 目标以包含“debug=true”,以启用代码的调试编译。

于 2011-05-09T10:49:00.007 回答
0

事实证明,StringTokenizer 版本有 bug,所以两个版本都内存不足。

于 2011-05-11T09:26:03.077 回答
0

Apache Solr使用commons-csv,所以我建议尝试一下。Solr 使用它是一个很大的认可。

于 2011-05-11T10:00:02.060 回答