2016-12-28 8 views
1

Я читаю большие файлы журнала с помощью BufferedReader в java.I нужно фильтровать содержимое файла и хранить данные в базе данных. пример.Чтение больших файлов и фильтра с помощью contains() java

BufferedReader br=new BufferedReader(new FileReader("test.log")); 
String line; 
while((line=br.readLine())!=null){ 
    if(line.contains("filter1") || line.contains("filter2") || 
     line.contains("filter3") || line.contains("filter4")...){ 
     //creating object and storing using hibernate 
    } 
} 

У меня есть более 50 таких фильтров, и проблема возникает при чтении файлов более 100 МБ. Многое время тратится на то, чтобы сопоставить эти строки фильтра.

Я не могу использовать Collection.contains (строка) в качестве фильтров, если условия являются подстроками строки, прочитанной. Затраченное время связано не с IO, а с фильтрацией содержимого и созданием объектов для хранения.

Редактировать 1: - filter1, filter2 только для простоты. В реальных случаях фильтр будет выглядеть как «новый файл», «отчет», «удаленный из папки», «схема», «переместить», «копировать», «добавить в очередь», «уникальный идентификатор» и т. Д. Эти являются конкретным ключевым словом, которое я проверяю, чтобы увидеть, содержит ли строка соответствующие данные для хранения.

Пожалуйста, предложите лучший способ достижения этого.

+0

Попробуйте использовать 'метод containsAny' из' org.apache.commons.lang3.StringUtils' https: //commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#containsAny-java.lang.CharSequence-java.lang.CharSequence...- –

+0

Как представлено, там вы не можете сделать, чтобы улучшить его. Если вам нужно проверить, содержит ли строка одну из 50 строк, вам, возможно, придется искать все 50 от начала до конца.Если у вас больше знаний о потенциальной позиции строки или что, если строка A не появляется, то это означает, что строка B не поддерживает и т. Д., Вы можете немного улучшить это. Или вы можете использовать специализированный метод для поиска с помощью trie, чтобы вам не пришлось сканировать всю строку каждой строки. – RealSkeptic

ответ

1

В Java 8 вы можете использовать Files.lines для чтения файла как Stream.

В этом примере показано, как использовать Stream для фильтрации содержимого, конвертировать весь контент в верхний регистр и возвращать его в виде списка.

c://lines.txt – A simple text file for testing 
line1 
line2 
line3 
line4 
line5 

import java.io.IOException; 
import java.nio.file.Files; 
import java.nio.file.Paths; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.stream.Collectors; 
import java.util.stream.Stream; 

public class TestReadFile { 

    public static void main(String args[]) { 

     String fileName = "c://lines.txt"; 
     List<String> list = new ArrayList<>(); 

     try (Stream<String> stream = Files.lines(Paths.get(fileName))) { 

      //1. filter line 3 
      //2. convert all content to upper case 
      //3. convert it into a List 
      list = stream 
        .filter(line -> !line.startsWith("line3")) 
        .map(String::toUpperCase) 
        .collect(Collectors.toList()); 

     } catch (IOException e) { 
      e.printStackTrace(); 
     } 

     list.forEach(System.out::println); 

    } 

} 
+0

Как это улучшит производительность? – assylias

+1

Files.lines в Java 8 будет читать все строки из файла как Stream of String, который заполняется лениво, когда поток потребляется. Итак, если у вас огромный файл, и вы читаете только первые 100 строк, тогда остальные строки не будут загружаться в память, что приведет к повышению производительности. –

+0

Вы можете использовать различные методы из класса java.util.stream.Streams для обработки строк, считанных из файла, прежде чем печатать их или возвращать их вызывающему. Это не просто выражение лямбда, которое введено в Java 8, есть много других подобных вещей, которые скрыты за аурой больших функций, таких как lambdas и streams. –

0

Это зависит от того, как выглядят ваши фильтры. Если это действительно были filter1, filter2 и т.д., то вы можете использовать регулярные выражения, как

private static final Pattern pattern = Pattern.compile("filter[0-9]"); 

... // in a loop 
if (pattern.matcher(line).matches()) {...} 

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

Например, вы можете использовать 4-граммы или так, используйте rolling hash как

/// Initialization 
Set<Integer> hashesOf4grams = new HashSet<>(); 
for (String s : filters) { 
    if (s.length() < 4) { 
     ... do some handling for short strings, omitted here as probably not needed. 
    } 
    int hash = 0; 
    for (int i = 0; i < 4; ++i) { 
     hash = (hash << 8) + s.charAt(i); 
    } 
    hashesOf4grams.add(hash); 
} 


/// Loop. 
for (String line : lines) { 
    boolean maybeMatching = false; 
    int hash = 0; 
    for (int i = 0; i < line.length() && !maybeMatching; ++i) { 
     hash = (hash << 8) + line.charAt(i); 
     maybeMatching = hashesOf4grams.contains(hash); 
    } 
    if (!maybeMatching) { 
     continue; 
    } 

    // Slow test. 
    boolean surelyMatching = false; 
    for (String s : filters) { 
     if (line.contains(s)) { 
      surelyMatching = true; 
      break; 
     } 
    } 
    if (surelyMatching) {...} 
} 

зыбучие выше гарантирует, что только 4 последних символы имеют значение. Вместо Set.contains (с боксом) вы можете использовать некоторую примитивную коллекцию.

Вы можете использовать tries ...

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

private static final Pattern pattern = Pattern.compile("new file|re(port|moved from folder)"); 

может работать лучше, чем тестирование всего отдельно. Я думаю, что попытки должны быть лучшими, но N-граммы проще и могут работать достаточно хорошо.

В моей выше реализации, я предполагаю, что все фильтры имеют длину по меньшей мере 4.


+0

filter1, filter2 были просто для простоты. –

+0

Я обновил вопрос. Пожалуйста, см. Редактировать 1 –

+0

@AnuragUpadhyaya Пожалуйста, добавьте больше строк. – maaartinus

Смежные вопросы