Чтение csv файла с миллионами строк через java как можно быстрее

Я хочу прочитать csv файлы, включая миллионы строк, и использовать атрибуты для моего алгоритма Tree Tree. Мой код ниже:

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. Есть ли совет? Благодарим, спасибо.

Ответ 1

В этом фрагменте я вижу две проблемы, которые значительно замедлят вас:

while ((line = br2.readLine()) != null) { 
    line=line.replaceAll(",,", ",NA,");
    String[] object = line.split(cvsSplitBy);
    rowList.add(object); 
    counterRow++;
}

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

Хуже, однако, чрезмерное раздутие данных в объект String []. Вам понадобятся столбцы/ячейки только тогда, когда вы вызываете для этой строки значение "РеализацияDecisionTreeRulesFor2012" - не все время, пока вы читаете этот файл и обрабатываете все остальные строки. Переместите разделение (или что-то лучше, как это было предложено комментариями) во вторую строку.

(Создание многих объектов плохое, даже если вы можете позволить себе память.)

Возможно, было бы лучше назвать ImplementDecisionTreeRulesFor2012, пока вы читаете "миллионы"? Это позволило бы полностью исключить массив ArrayList.

В дальнейшем Отсрочка разделения сокращает время выполнения для 10 миллионов строк от 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.983s. Это примерно в 30 раз быстрее, чем исходный код, который в любом случае запускается в OutOfMemory.

Ответ 2

Просто используйте синтаксический анализатор CSV uniVocity-parsers вместо того, чтобы пытаться создать свой собственный парсер. Вероятно, ваша реализация не будет быстрой или гибкой, чтобы обрабатывать все угловые случаи.

Это чрезвычайно эффективная память, и вы можете анализировать миллион строк менее чем за секунду. Эта ссылка имеет сравнение производительности многих java файлов CSV-библиотек, а сингл-парсер - сверху.

Вот простой пример того, как его использовать:

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);

Наконец, в нем есть встроенные процедуры, которые используют парсер для выполнения некоторых общих задач (итерация java beans, dump ResultSet и т.д.),

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

Раскрытие информации: Я являюсь автором этой библиотеки. Это с открытым исходным кодом и бесплатно (лицензия Apache V2.0).

Ответ 3

поверх вышеупомянутого единства стоит проверить

3 из них будут как время комментария самым быстрым парсером csv.

Скорее всего, вы можете написать свой собственный парсер медленнее и глючить.

Ответ 4

Если вы нацелены на объекты (например, привязки данных), я написал высокопроизводительную библиотеку sesseltjonna-csv, которую вы можете найти интересной. Сравнение тестов с SimpleFlatMapper и uniVocity здесь.