2012-11-05 14 views
5

to stycznie związane an earlier question of mine.Czy odczytać plik, używając wyrażenia regularnego?

Zasadniczo rozwiązanie w tej kwestii działał świetnie, ale teraz muszę się przystosować go do pracy w znacznie większym zastosowaniu analizy. Po prostu użycie StreamReader.ReadToEnd() jest nie do przyjęcia, ponieważ niektóre z plików, które będę czytać, są bardzo, bardzo duże. Jeśli pojawił się błąd i ktoś zapomniał oczyścić, teoretycznie mogą być gigabajty. Oczywiście nie mogę po prostu czytać do końca tego.

Niestety, normalne linie odczytu są również niedopuszczalne, ponieważ niektóre wiersze danych, które odczytuję zawierają ślady stosów - w ich formatowaniu są oczywiście używane /r/n. Idealnie, chciałbym powiedzieć programowi, aby czytał dalej, dopóki nie trafi na dopasowanie do wyrażenia regularnego, które następnie zwraca. Czy jest jakaś funkcjonalność do tego w .net? Jeśli nie, czy mogę uzyskać jakieś sugestie dotyczące tego, jak je napisać?

Edit: Żeby było trochę łatwiej śledzić moje pytanie, oto pasta z niektórych ważnych częściach przystosowanego kodu:

foreach (var fileString in logpath.Select(log => new StreamReader(log)).Select(fileStream => fileStream.ReadToEnd())) 
{ 
    const string junkPattern = @"\[(?<junk>[0-9]*)\] \((?<userid>.{0,32})\)"; 
    const string severityPattern = @"INFO|ERROR|FATAL"; 
    const string datePattern = "^(?=[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3})"; 
    var records = Regex.Split(fileString, datePattern, RegexOptions.Multiline); 
    foreach (var record in records.Where(x => string.IsNullOrEmpty(x) == false)) 
    ...... 

Problem polega na foreach. .Select(fileStream => fileStream.ReadToEnd()) źle wysadzi pamięć, po prostu to wiem.

+4

I masz jeden z głównych powodów, dla których nie bardzo zależy mi na użyciu RegEx do takich zadań. Jeśli napisałeś prosty parser, możesz go po prostu dostosować do obsługi nowych linii. –

+0

@ JonathanWood Wyrażenia regularne są niesamowite do analizowania poszczególnych rekordów po tym, jak mam cały rekord. Po prostu wyskakuję wszystkie potrzebne informacje i przechodzę od razu do powiązanych pól. Problem polega na tym, że w tym przypadku plik jest wprowadzany, wydaje się, że po prostu nie jest wystarczająco elastyczny, aby dać mi pojedynczy rekord na raz z plikiem, który mam. Ale to wydaje się fałszywe, prawda? To nie może być rzadki problem. – tmesser

+1

Tak więc ślad stosu ma/r/n. Dlaczego to eliminuje readline? – Paparazzi

Odpowiedz

1

Po pierwsze, powinieneś przenieść definicję const do deklaracji klasy - kompilator zrobi to za ciebie, ale powinno to być zrobione samemu, tylko po to, aby poprawić czytelność kodu.

Jak wspomniano @Blam, należy użyć StringBuilder i StreamReader.ReadLine w pary, coś jak to:

foreach(var filePath in logpath) 
{ 
    var sbRecord = new StringBuilder(); 
    using(var reader = new StreamReader(filePath)) 
    { 
     do 
     { 
      var line = reader.ReadLine(); 
      // check start of the new record lines 
      if (Regex.Match(line, datePattern) && sbRecord.Length > 0) 
      { 
       // your method for log record 
       HandleRecord(sbRecord.ToString()); 
       sbRecord.Clear(); 
       sbRecord.AppendLine(line); 
      } 
      // if no lines were added or datePattern didn't hit 
      // append info about current record 
      else 
      { 
       sbRecord.AppendLine(line); 
      } 
     } while (!reader.EndOfStream) 
    } 
} 

Gdybym nie rozumieją coś o swoim problemie, proszę wyjaśnić to w komentarzu.
Możesz także użyć ThreadPool, aby zaplanować zadania dla swoich linii, tylko dla szybkości aplikacji.

+0

Zakończyłem kodowanie mojego własnego rozwiązania, które zajmuje się strumieniem na niskim poziomie, ponieważ uważałem, że to absolutny absurd, że nie mogę przetworzyć strumienia tekstowego jako znormalizowanego tokena. Jednak w zasadzie dla kogokolwiek innego jest to mniej więcej to, co musisz zrobić. – tmesser

+0

@YYY Czy możesz podać swój kod tutaj, tylko dla nagrania? Myślę, że byłoby to interesujące. – VMAtm

+0

Mimo że chciałbym to zrobić, wkrótce stanie się częścią jakiegoś oprogramowania bankowego i dlatego jest zastrzeżone. To powiedziawszy, kiedy dostaję kilka dni wolnego od pracy, jedną z rzeczy w moim programie jest stworzenie wersji open source i dodanie jej do mojego githuba, więc mogę rozszerzyć rozwiązanie. W tej chwili zasadniczo czytam w stałej liczbie bajtów i utrzymuję pozycję pliku, która działa świetnie w kontekście naszego projektu, ale nie jest dobrym ogólnym rozwiązaniem. Ta ambicja będzie kontynuowana po skopiowaniu/oczyszczeniu mojej początkowej pracy i dodaniu jej do github. – tmesser

Powiązane problemy