2013-10-26 6 views
2

годами я разбирал файлы csv во время моих ночных пакетных заданий, используя следующую логику без проблем. Как бы то ни было, я полностью переписываю приложение, и теперь мне интересно, может ли быть какая-то производительность/качество при использовании чего-то вроде opencsv? У меня нет опыта работы с другими библиотеками, так что я надеялся, что кто-то еще с опытом мог бы звонить в.opencsv vs java split comma

while ((line = br.readLine()) != null) { 
    String[] items = line.split(","); 


     for (int i = 0; i < items.length; ++i) { 
      // Remove extra quote 
      if (items[i].length > 2) { 
       items[i] = items[i].replaceAll("\"", ""); 
      } 

      // Replace blank items with nulls 
      if (items[i].matches("^\\s*$")) { 
       items[i] = null; 
      } 

     } 

     String item0 = item[0]; 
     String item1 = item[1]; 
} 

ответ

3

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

+0

Очень хороший момент, двойная цитата определенно уродлива. Я также заметил, что после прочтения api вы можете передать массив переменных String в парсер ssv, а затем просто передать анализируемый объект объекту объекта. Мне очень нравится эта функция, я думаю, что это поможет создать единый динамический парсер. –

+2

Чтение Csv будет «IO Bound», поэтому не так много улучшений во время выполнения. Но ваш текущий подход включает в себя несколько проходов через каждую строку (и использует регулярное выражение); хорошо написанный Csv Parser должен требовать только один проход через каждую строку (и, надеюсь, меньше CPU).Сокращение использования ЦП никогда не повредит. –

4

Ответ chrylis прав, что вы не можете получить производительность, но да opencsv будет обрабатывать все случаи для вас.
Но если вы действительно беспокоитесь о производительности, то немного подправить в вашем коде может помочь вам улучшить производительность,
После анализа кода для String.Split который

public String[] split(String regex) { 
     return split(regex, 0); 
    } 
    public String[] split(String regex, int limit) { 
      return Pattern.compile(regex).split(this, limit); 
    } 

Для каждого из вашей строки новый шаблон компилируется код Pattern.compile является

public static Pattern compile(String regex, int flags) { 
    return new Pattern(regex, flags); 
} 

Приведенный выше код, чтобы создать шаблон объект снова повторяется в,

items[i].matches("^\\s*$") 

Так что, если ваши файлы, имеющие миллионы строк, то создавая миллионы объектов шаблона могут быть накладными расходы, так что вы можете изменить свой код как,

Pattern pat = Pattern.compile(","); 
    Pattern regexPattern = Pattern.compile("^\\s*$");  
    while ((line = br.readLine()) != null) 
    { 
     String[] items = pat.split(line, 0); 
     for (int i = 0; i < items.length; ++i) 
     {   
      if (items[i] != null && items.length > 2) // I think it should be items[i].length() > 2 
      { //We can also remove this null check as splitted strings will never be null 
       items[i] = items[i].replaceAll("\"", ""); 
      }    
      if (regexPattern.matcher(items[i]) .matches()) { 
       items[i] = null; 
      } 
     }   
    } 

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

+0

Спасибо dbw, да, я обрабатываю миллионы строк, поэтому любое улучшение поможет. В настоящее время я могу обрабатывать около 1 миллиона строк каждые две минуты, используя 8 ядер. Я знаю, что на данный момент это чисто академический, но, учитывая, что я полностью переписываю, отлично провести время, чтобы увидеть, что еще там может сократить накладные расходы. –

+0

@George еще одна вещь, я считаю, что строки items.length> 2 должны быть элементами [i] .length()> 2 – dbw

+0

Nice find :) Интересно, сколько лет эта ошибка существует. –

0

Чтобы добавить к вашим вариантам, рассмотрите Jackson CsvMapper.

Я разобрал 36 миллионов строк из 4k файлов за 12 минут, используя Jackson CsvMapper на macbook pro. Это использует его для непосредственной привязки к POJO в некоторых местах и ​​использования его для чтения Object [] для каждой строки в других и применения огромного количества вспомогательной обработки для нормализации входных данных.

Это также очень проста в использовании:

, как Object []

CsvMapper mapper = new CsvMapper(); 
    mapper.enable(CsvParser.Feature.WRAP_AS_ARRAY); 
    File csvFile = new File("input.csv"); // or from String, URL etc 
    MappingIterator<Object[]> it = mapper.reader(Object[].class).readValues(csvFile); 

в POJOs

public class CSVPerson{ 
     public String firstname; 
     public String lastname; 
     //etc 
    } 

    CsvMapper mapper = new CsvMapper(); 
    CsvSchema schema = CsvSchema.emptySchema().withHeader().withColumnSeparator(delimiter); 
    MappingIterator<CSVPerson> it = = mapper.reader(CSVPerson).with(schema).readValues(input); 
    while (it.hasNext()){ 
     CSVPerson row = it.next(); 
    } 

Я всегда поющих дифирамбы этой библиотеки, это здорово. Это также очень гибко.

+0

Я никогда не давал Джексону мысль, мне придется глубже заглянуть в нее. Я предполагаю, что вы многопоточность для достижения этого числа? Я использую ту же машину. –

+0

Нет, но это число не включает в себя сохранение базы данных, где находится мое (пока нерешенное) узкое место. Это стоит попробовать против ваших других решений imo. Этот ответ о split() может помочь вам немного: http://stackoverflow.com/questions/19356021/stringtokenizer-reading-lines-with-integers/19356088#19356088 – tom

+0

Я только что проверил. Я могу анализировать строки в POJO с помощью CsvMapper быстрее, чем я могу разобрать с помощью Split() – tom