Eine bestimmte Zeile aus einer großen .txt auslesen



  • Hallo,

    ich habe eine große .txt-Datei, aus der ich genau eine Zeile (z. B. Zeile 7861) welche maximal 40 Zeichen lang ist, in einem char[] speichern, um sie weiterzuverwenden (z. B. verkürzen oder ausgeben).

    Selbstverständlich möchte ich dabei nicht das ganze Dokument durchlesen und speichern.

    Wie ich eine .txt von Anfang an lese, ist mir klar, aber wie geht das mit einer bestimmten Zeile?

    Wäre nett wenn ihr mir helfen könntet.

    Gruß,
    MGOS



  • MGOS schrieb:

    Wie ich eine .txt von Anfang an lese, ist mir klar, aber wie geht das mit einer bestimmten Zeile?

    Gar nicht.
    Außer Du hast Dir vorher schon durch Komplettlesung einen Index erstellt, wo zu jeder Zeilennummer die Dateiposition vermerkt ist. Oder die Zeilen künstlich alle auf genau 40 Zeichen gebracht hast.



  • Erstmal: Danke für die schnelle Antwort

    Theoretisch könnte ich ganz am anfang für jede Zeile den Index speichern, müsste ich whrscheinlich auch tun, das ist einfacher als jede zeile auf 40 Zeichen zu stellen.
    Wie kann ich mit dem Index arbeiten? Muss ich dazu das ganze Dokument zuerst speichern? (das will ich vermeiden)



  • MGOS schrieb:

    Theoretisch könnte ich ganz am anfang für jede Zeile den Index speichern, müsste ich whrscheinlich auch tun, das ist einfacher als jede zeile auf 40 Zeichen zu stellen.

    Ja, aber einfacher ist es, eine zweite Datei (normalerweise mit Dateiname *.idx) nur für den Index zu erstellen.

    MGOS schrieb:

    Wie kann ich mit dem Index arbeiten? Muss ich dazu das ganze Dokument zuerst speichern? (das will ich vermeiden)

    Hä? Ich dachte, die Zeilendatei läge auf der Platte.



  • Ja, auf der Platte ist sie, aber ich möchte keine Kopie im Programm als Riesiges Array haben.



  • volkard meint dass du eine datei hast (auf deiner HDD), die du einliest.
    liest du sie das erste mal ein, erstellst du eine zweite datei (am besten im selben verzeichnis) die die indizes speichert

    irgendwo hast du (wenigstens temporär) mal ein grosses array, vllt auch nicht je nachdem wie du drangehst



  • MGOS schrieb:

    ich habe eine große .txt-Datei, aus der ich genau eine Zeile (z. B. Zeile 7861) welche maximal 40 Zeichen lang ist, ...

    Hallo MGOS,

    Die Länge der Zeilen ist egal. Versuche das:

    #include <iostream>
    #include <fstream>
    #include <limits>
    
    std::istream& skipline( std::istream& in )
    {
        return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' );
    }
    
    int main()
    {
        using namespace std;
        ifstream datei("gross.txt");
        for( int ln = 1; ln < 7861; ++ln )
            datei >> skipline;
        // -- ab hier aus Zeile 7861 lesen
        double zahl;
        int nr;
        datei >> zahl >> nr; // >> egal
        return 0;
    }
    

    siehe auch 'Textfile ab Zeile x einlesen'
    Gruß
    Werner



  • Danke, das hat mir sehr geholfen und das Programm funktioniert gut. Ich habe jetzt ein char-Array genommen, da im Dokument auch Text steht.

    #include <iostream> 
    #include <fstream> 
    #include <limits> 
    
    std::istream& skipline( std::istream& in ) 
    { 
        return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ); 
    } 
    int main() 
    { 
        using namespace std; 
        ifstream datei("test.txt"); 
        int iLine;
        cin >> iLine;
        for( int ln = 0; ln < iLine; ++ln ) 
            datei >> skipline; 
        char szText[40];
        datei.getline(szText,40);
        cout << szText << endl;
        getchar();
        getchar();
        return 0; 
    }
    

    So, jetzt möchte ich willkürlich um dokument 'herumspringen' - d. h. ich lese und gebe zuerst Zeile 1486, dann Zeile 8621 und dann 2683 oder 5906 aus.
    ich möchte das Dokument zwischendurch nicht immer öffnen und schließen. Gibt es ein Funktion wie gotoxy() oder "\r" ?



  • MGOS schrieb:

    Ich habe jetzt ein char-Array genommen, da im Dokument auch Text steht.

    Das wird Werner sehr freuen.

    MGOS schrieb:

    So, jetzt möchte ich willkürlich um dokument 'herumspringen' - d. h. ich lese und gebe zuerst Zeile 1486, dann Zeile 8621 und dann 2683 oder 5906 aus. ich möchte das Dokument zwischendurch nicht immer öffnen und schließen.

    Wir groß ist Deine Datei eigentlich? Warum ist der Rechner so lahm? Ich fürchte, wir tanzen hier um unsinnige Vorgaben herum.



  • Nehmen wir mal an, deine Datei hat 100.000 Zeilen, nehmen wir an jede Zeile hat maximal 40 Zeichen. Multiplizieren wir das mal: 4.000.000 characters. Das sind nach Adam Riese etwa 3.8 Megabyte an Daten ... was spricht dagegen das in einen Vector von Strings zu packen - dann hast du schnellen Zeilenweisen Zugriff über das [] oder .at() des Vektors.

    Das Bottleneck ist bei heutigen PCs in der Regel nicht der Speicher oder die Geschwindigkeit, sondern der IO-Zugriff (also genau das, was du da mit fseak oder dauerndem wiedereinlesen) machst. Ich arbeite mit csv-Dateien die haben (runlength-endcoded) 11-20 MB (~600 Messungen pro Sekunde, 1024 ints per Messung, 30 Sekunden und länger) und ziehe die Problemlos in den Speicher zum weiterarbeiten (das parsen dauert etwas ;). Bei popeliegen 8k-10k Zeilen a 40 char's (die du hier als Beispiel bringst) sind das gerade mal 380kb oder so an Daten. Pillekram - sozusagen. Achja und bezüglich der string->char-arrays ... TOLL. Du hast dann 4000 Zeilen die vielleicht nur 10 Zeichen lang sind, reservierst aber immer 40 dafür. Warum dann überhaupt sparen - string nutzt soviel wie nötig und nicht viel mehr.



  • volkard schrieb:

    MGOS schrieb:

    Ich habe jetzt ein char-Array genommen, da im Dokument auch Text steht.

    Das wird Werner sehr freuen.

    😃

    MGOS schrieb:

    char szText[40];
        datei.getline(szText,40);
    

    hallo MGOS, .. wo lernt man so in C++ zu programmieren (früher war ich gegen Bücherverbrennung)?

    MGOS schrieb:

    So, jetzt möchte ich willkürlich um dokument 'herumspringen' - d. h. ich lese und gebe zuerst Zeile 1486, dann Zeile 8621 und dann 2683 oder 5906 aus.
    ich möchte das Dokument zwischendurch nicht immer öffnen und schließen. Gibt es ein Funktion wie gotoxy() oder "\r" ?

    Ich könnte Dir sowas schnitzen, aber irgendwie ist das der falsche Ansatz - siehe auch den Beitrag von padreigh.

    Gruß
    Werner



  • padreigh schrieb:

    Achja und bezüglich der string->char-arrays ... TOLL. Du hast dann 4000 Zeilen die vielleicht nur 10 Zeichen lang sind, reservierst aber immer 40 dafür. Warum dann überhaupt sparen - string nutzt soviel wie nötig und nicht viel mehr.

    Mööp!
    Nehmen wir eine unwahrscheinliche Implementierung für std::string, die nur einen Zeiger auf begin und einen Zeiger auf end hat. Und netterweise 32-Bit-Zeiger.
    Dann sind das 8 Bytes für das String-Objekt. Und x Bytes, die Nutzdaten. Bei einer allocation granularity von 32 Byte(recht normal) werden das am Ende mindestens 40 Byte pro String gefressen.
    Copy-On-Write-Strings, wie bei mir, könnten es bei 36 Bytes belassen.
    Mir scheint, Dein Verschwendungsargument zeiht nicht.



  • Das mit Char-Array vs. String versteh ich - vielleicht ist es in der Tat besser, hier einen String zu verwenden. Man sagt jedoch, strings könne man schlechter manipulieren als Arrays...

    @ Werner:
    Falscher Ansatz, das versteh' ich auch, aber wie soll ich es sonst machen?

    das ganze Dokument auf einmal in ein Array/string fressen und die Indizes für jede Zeile speichern? Es muss doch irgendeine Möglichkeit geben, Bestimmte Stellen aus dem Dokument zu lesen.



  • Ok, ich geb zu, ich mag keine char* 's ;).

    Um den Overhead von 10k Zeilen in einem vector<string> zu verringern könnte man ja nur einen String nehmen, immer fleissig die Zeilen appenden und nur die Indexe in einen std::vector<int> speichern *g* Klasse drum, feddich. Oder man nimmt ihn einfach in Kauf *eg*.

    String schlechter manipulierbar als char arrays? Höh? Guck dir mal die std::string API an, die bietet eine Menge als einzeiler was man mir chars erst basteln muss!


  • Mod

    MGOS schrieb:

    Man sagt jedoch, strings könne man schlechter manipulieren als Arrays...

    Wer das sagt, hat einen Schaden. Einen großen noch dazu. Das Gegenteil ist der Fall.



  • Wenn du Zeile 7861 willst, warum nicht einfach:

    std::ifstream file(filename);
      int n = 1;
      while (file && n < 7861)
        if (file.get() == '\n')
          ++n;
      std::string line;
      std::getline(file, line);
    

    😕

    EDIT: Ok, praktisch das gleiche wurde ja schon gepostet...

    Wenn wirklich alle "Zeilen" maximal 40 Zeichen lang sein können und du oft so einen Zugriff brauchst würd ich mir aber wirklich (wie volkard schon angedeutet hat) überlegen ob du statt einer Textdatei nicht lieber einfach eine Binärdatei nimmst in der jede Zeile 40 Byte belegt. Dort kannst du dann nämlich einfach direkt zur Stelle Zeilennummer * 40 hinspringen ohne alles zu durchsuchen...



  • Ok, Textdatein sind aber denke ich mal einfacher für den user zu handeln (mit einem normalen Texteditor).

    Hier ist eine Lösung, die ich mit strings gefunden habe, und funktioniert wunderbar.

    #include <iostream> 
    #include <fstream> 
    #include <string> 
    
    using namespace std; 
    
    int main() 
    { 
        ifstream datei("test.txt");    //Datei öffnen
        string sLine;                  //Aktuelle Zeile
        string sText;                  //Ganzer Text
        sText.clear();                 //Löschen, falls etwas drinsteht
        do{
            getline(datei,sLine,'\n'); //eine Zeile auslesen
            sText += sLine + '\n';     //und dem Text hinzufügen +  Return
        }while (sLine != "");          //Solange rauskopiern bis zu einer leeren Zeile
        cout << sText;                 //Text ausgeben
        getchar();
        getchar();
        return 0; 
    }
    


  • MGOS schrieb:

    Ok, Textdatein sind aber denke ich mal einfacher für den user zu handeln (mit einem normalen Texteditor).

    Also gehts um maximal 10000 Zeilen und die ganzen Anforderungen waren nicht nötig?



  • MGOS schrieb:

    @ Werner:
    Falscher Ansatz, das versteh' ich auch, aber wie soll ich es sonst machen?

    das ganze Dokument auf einmal in ein Array/string fressen und die Indizes für jede Zeile speichern? Es muss doch irgendeine Möglichkeit geben, Bestimmte Stellen aus dem Dokument zu lesen.

    Indem Du kurz schilderst, was Dein Programm sonst so noch tut.
    Wo, wie und zu welchem Zeitpunkt erfährt Dein Programm aus welcher Zeile es etwas herauslesen soll? Was ist das, was da gelesen wird - wird das wirklich nur als Zeile genauso ausgegeben oder wird es irgendwie interpretiert und noch auf den Inhalt reagiert? Muss die Ausgabe sofort geschehen, oder kann das am Ende des Programms (bzw. später) gemacht werden?

    Gruß
    Werner



  • @ Volkard
    Ja, maximal 10000 Zeilen, mehr wird es nicht sein. Aber es sollte auch auf einem langsamen Rechner laufen können, und man nicht erst 15 Minuten warten muss bis es komplett bearbeitet wurde

    Das Programmm bekommt eine Textdatei mit beliebiger Größe, welche eventuell mit einem komplett unabhängigen andern Programm erstellt wurde.
    Die ersten 4 Zeichen einer Zeile stellen eine Art Zeilennummer dar.
    Die nächsten 4 Zeichen sind Codes für Befehle, was als nächstes gemacht werden soll.
    Dann folgen zuerst ein Leerzeichen, dann bis zu 30 Zeichen Text oder Zahlen.
    Das Programm erfährt entweder durch die Codes und die folgende Zahl, wohin es springen soll, oder durch eine Benutzereingabe.

    Die Zeilen sollten deshalb sofort ausgegeben werden, wenn sie erreicht wurden.

    Bespiel:

    5B7 GOTO 3CA
    

Log in to reply