ifstream::read(..) und aktuelle zeilennummer in textdatei



  • hallo,

    fuer ein logfile-tool (textdatei) habe ich eine funktion die bei sehr grossen logfiles (mehrere 100MB gross) die logfiles chunk-weise abarbeitet (heisst: es wird z.B. ein MB eingelesen, analysiert und danach das naechste MB eingelesen usw.).
    Das ist deshalb noetig, weil ich mit boost::regex (regulaere ausdruecke) nach bestimmten mustern suchen moechte, die sich ueber zeilen hinweg erstrecken koennen.

    nun meine frage: ist es irgend moeglich die anzahl an eingelesenen zeilen herauszubekommen bei folgendem code ??? :

    unsigned long chunksize = 1048576;
    char *buffer = new char[chunksize];
    if( buffer )
    {
      ifstream in("test.log");
      if( in.is_open() )
      {
       in.read(buffer, chunksize); 
       // hier rausbekommen, wieviel zeilen eingelesen wurden
      }
      delete [] buffer;
    }
    

    vielen dank.



  • du könntest einfach durch deinen Chunk gehen und die '\n's Zählen ... ("\r\n",'\r' je OS)



  • pepe75 schrieb:

    .. ist es irgend moeglich die anzahl an eingelesenen zeilen herauszubekommen bei folgendem code ??? :

    ifstream in("test.log");
      in.read(buffer, chunksize); 
       // hier rausbekommen, wieviel zeilen eingelesen wurden
    

    in.gcount() liefert die Anzahl der zuletzt gelesenen Zeichen beim unformatierten Lesen.



  • Werner: Anzahl der Zeilen, nicht Zeichen.



  • @padreigh: bei mehrere MB grossen chunks (und entsprechend grossem string) ist das bestimmt nicht so effizient zeichenweise die newlines zu zaehlen.

    @Michael E.: genau 😃

    mir faellt momentan nix besseres ein als statt ifstream::read(..) ifstream::getline(..) zu verwende und selber mitzuzaehlen (chunk wird dann zeilenweise vergroessert), aber das duerfte auch um einiges langsamer sein als den chunk per read(..) einzulesen 😕



  • pepe75 schrieb:

    @padreigh: bei mehrere MB grossen chunks (und entsprechend grossem string) ist das bestimmt nicht so effizient zeichenweise die newlines zu zaehlen.

    Ist die einzige Möglichkeit. Ich kenne zumindest kein OS, welches die Zeilen von Dateien einzeln speichert/indiziert oder so etwas.

    Wofür brauchst du überhaupt die Anzahl der Zeilen?



  • @TyRoXx der besagte Algorithmus, welchen ich entwickele, soll aus einer beliebigen Zeichenkette bestimmte muster extrahieren.
    diese muster sind entweder einfache zeichenketten, oder aber regulaere ausdruecke (hierfuer verwende ich die boost::regex lib).

    das ausweiten der zu untersuchenden zeichenketten ueber mehrere zeilen hinweg ist daher interessant, weil es sich bei besagten textdateien um log-files handelt, und diese muster enthalten, die sich ueber mehrere zeilen erstrecken koennen, kurz: es geht um ein log-file-analyse tool.

    bei chunkweisem einlesen besteht aber das problem das ergebniss des algorithmus in einer dem benutzer moeglichst brauchbaren form darstellen zu koennen:

    also --> ich muss wissen, wo genau in der textdatei (ab welcher zeile) das muster gefunden wurde, daher der wunsch.



  • Arbeitet Dein Analyser denn zeilenweise? Osder kann es auch vorkommen, dass mehrere Zeilen benötigt werden, um ein sinnvolles Ergebnis zu erzielen?
    Grundsätzlich bietet sich auf jeden Fall, wie bereits erwähnt, std::getline an. Insbesondere wenn für jedes Ergebnis eine einzelne geschlossene Zeile ausreicht.



  • fuer diejenigen die es interessiert:

    ich habe mal fuer folgende beiden ansaetze geschaut was schneller geht:

    1. chunkweise per read(..) einlesen und danach im eingelesenen die newlines zaehlen

    oder

    1. zeilenweise einlesen bis gewuenschte chunkgroesse erreicht und dabei zeilen mitzaehlen

    ansatz 1) ist um vielfaches schneller als 2):
    bei einem 120 MB (!) grossen chunk braucht ansatz 2) um ein vielfaches laenger als 1) (bei meiner durchschnittsmaschine ca. 1 Sekunde, was recht vertretbar ist 👍 ) .

    trotdem danke an alle.



  • und was überrascht dich jetzt daran? Du musst bei (2) deine Datei (IO-Operation) ca 10000000 mal anfassen - das ist das, was Zeit kostet. Einige MB an Daten zu durchwühlen ist zwar lästig aber schnell. Daher ja mein Vorschlag oben 😉 Warscheinlich gibts da auch ein nettes find_if oder so in der std::bib - aber wenn du nur einen Counter hochzählen willst ist das Zeichenweise durchgeheb einfach - du könntest das sogar in Threads auslagern und dem immer 12MB oder so an Daten zukommen lassen und dann die counter aufaddieren wenns noch schneller sein soll oder openmp drauf los lassen oder so *g*



  • @padreigh so offensichtlich ist das nicht gewesen (fuer mich zumindest):

    eine zeichenkette die mehrere 100MB lang ist mal eben nach newlines zu untersuchen (in diesem fall wiederholtes std::string::find(..)) ist nichts, was sofort auf geschwindigkeit vermuten liesse.

    das wiegt aber die vermehrten IO-operationen im ansatz 2) klar auf, wie ich nun weiss.

    man lernt halt immer dazu 😉



  • (in diesem fall wiederholtes std::string::find(..)) ist nichts, was sofort auf geschwindigkeit vermuten liesse

    lol - sicher nicht. Lerne und Staune, hier kommt Metawissen 😃

    google "c++ count" , 2ter Treffer

    count - C++ Reference
    - [ Diese Seite übersetzen ]
    template <class InputIterator, class T> typename iterator_traits ...
    www.cplusplus.com/reference/.../count/ - Im Cache - Ähnliche Seiten

    http://www.cplusplus.com/reference/algorithm/count/

    guckst dir an (das Beispiel unten für schnell-Leser) und du kitzelst noch mehr Performance raus, schließlich interessieren dich ja die ganzen Zwischenpositionen nicht? Nur die Anzahl? Gerade bei so generischen Fragestellungen (wie oft ist X in Y drin) lohnt sich ein Blick in die STL, und das sollte um Längen schneller sein als alles was du per Schleife gemacht hast 😉 zumindest wenn du auf der std::string Referenz die begin() end() findest 😉

    Das traurige daran (wenn du weiterliest)

    Complexity
    Linear: Performs as many comparisons as the number of elements between first and last.

    Also kannst du vermutlich auch selbst Zeichenweise durchhecheln

    size_t c=0;
    for (size_t i=0; i<data.size(); ++i) if (data[i]=='\n') ++c;
    

    selbst das könnte schneller sein als das string::find() da dort Methodenaufrufe und zugehöriges wegfallen könnten - dunno - Implementationsbedingt.



  • @padreigh:
    nur fuer interessierte:

    std::algorithm::count(..) ist um ein vielfaches langsamer als wiederholtes std::string::find(..) (zu fuss jedes char auf newline abzufragen ebenfalls).

    fazit: std::string::find(..) bleibt fuer obiges problem (zumindest) mein favorit 👍

    keine ahnung, wie die STL das intern mit find regelt, aber es ist sehr viel schneller, wie gesagt: fuer einen string der 120MB lang ist, braucht ein find aufruf knapp ne sekunde, alle anderen ansaetze (s.o.) meherere sekunden



  • pepe75 schrieb:

    @padreigh:
    nur fuer interessierte:

    std::algorithm::count(..) ist um ein vielfaches langsamer als wiederholtes std::string::find(..) (zu fuss jedes char auf newline abzufragen ebenfalls).

    fazit: std::string::find(..) bleibt fuer obiges problem (zumindest) mein favorit 👍

    keine ahnung, wie die STL das intern mit find regelt, aber es ist sehr viel schneller, wie gesagt: fuer einen string der 120MB lang ist, braucht ein find aufruf knapp ne sekunde, alle anderen ansaetze (s.o.) meherere sekunden

    Sicher? Mit Optimierungen? Zeig mal den Code.


Anmelden zum Antworten