чтение небольшого файла CSV в Java, что приводит к ошибке нехватки памяти - PullRequest
1 голос
/ 09 мая 2011

У меня есть две следующие реализации чтения csv-файлов, рассматриваемые csv-файлы не такие большие (5 мегабайт).

Первая реализация использует openCSV, вторая - stringTokenizer.

В первом случае произошла ошибка нехватки памяти, даже когда я увеличил объем кучи java max до 1G (Xmx), хотя реализация StringTokenizer не устойчива, но у меня нет выбора, так как мне нужно прочитать файл csv в память .

Я не понимаю, почему версия openCSV потребляет так много памяти, учитывая небольшой размер файла csv (в нем 200 тыс. Строк, но только размер файла около 5 м). Что делает OpenCSV Reader, который потребует столько памяти? Версия 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;
}

Ответы [ 3 ]

0 голосов
/ 11 мая 2011

оказывается, что в версии StringTokenizer есть ошибка, поэтому обеим версиям не хватает памяти.

0 голосов
/ 11 мая 2011

Apache Solr использует commons-csv , поэтому я рекомендовал бы попробовать. Solr, использующий это, является большим одобрением.

0 голосов
/ 09 мая 2011

Возможно, вряд ли, но я бы предположил, что ваши входные данные могут вызывать ошибку в библиотеке opencsv, возможно, приводящую к застреванию в цикле.

Загрузка для opencsv предоставляет исходные тексты и библиотеки, поэтому вы сможете самостоятельно отлаживать код.

Поскольку трассировка стека не показывает номера строк для кода opencsv, я думаю, вам нужно изменить цель javac в сценарии сборки, чтобы включить «debug = true», чтобы включить отладочную компиляцию кода.

...