Probleme beim Einlesen einer Text-Datei



  • Hallo,

    ich habe ein Problem mit der Dateieingabe.

    Das Schreiben in eine Datei ist kein Problem,
    aber wie kann ich z.B. eine Datei ab einer bestimmten Stelle und bis zu einer bestimmten einlesen ?

    z.B: Beispiel.txt

    11 12 13 15; 13 23 23 34;

    Ich würde gerne die 4 Zahlen zwischen den Semikoli in ein Feld einlesen ?

    Ich bin für jede Hilfe dankbar ! 🙂



  • mal auf die Schnelle:

    ifstream file("foo.txt");
    	string line;
    	string::size_type start = 0;
    	string::size_type end = 0;
    	getline(file, line);
    	int n[4];
    
    	while ((end = line.find_first_of(';', start)) != string::npos)
    	{
    	    istringstream istr(line.substr(start, end - start));
    	    istr >> n[0] >> n[1] >> n[2] >> n[3];
    	    start = end + 1;
    
    	    // jetzt stehen in n[] jeweils 4 Zahlen :)
    	}
    

    EDIT: hatte kleinen Tippfehler drinnen... jetzt gehts 🙂

    Wenn dir der Code unklar ist, frag nach 🙂



  • Hallo,

    Danke.

    aber hier nochmal eine Frage dazu:

    ich lese einfach einige Zahlen aus einer Datei ein, aber es klappt nicht so ganz:

    #include <iostream>
    #include <fstream>
    using namespace std;
    main()
    {
    int x,a[10],i=0;
    ifstream fin ("Datei.txt");
    fin.open();
    
    while(!fin.eof())
    {
      fin>>x;
      a[i]=x;
      i++;
    }
    fin.close();
    
    }
    

    Das Einlesen müsste doch theoretisch gehen ?



  • lightning schrieb:

    Hallo,

    Danke.

    aber hier nochmal eine Frage dazu:

    ich lese einfach einige Zahlen aus einer Datei ein, aber es klappt nicht so ganz:

    #include <iostream>
    #include <fstream>
    using namespace std;
    main()
    {
    int x,a[10],i=0;
    ifstream fin ("Datei.txt");
    fin.open();
    
    while(!fin.eof())
    {
      fin>>x;
      a[i]=x;
      i++;
    }
    fin.close();
    
    }
    

    Das Einlesen müsste doch theoretisch gehen ?

    wenn du den Code ausprobierst, wirst du bemerken, dass du gleich am ersten Semikolon scheitern wirst 😉

    Ansonsten noch:

    in C++ muss es

    int main()
    // oder:
    int main(int argc, char* argv[])
    

    heissen... nur "main()" allein ist eigentlich falsch!

    und das fin.open() muss auch nicht sein. Du hast ja bereits in der Zeile

    ifstream fin("Datei.txt");
    

    angegeben, welche Datei du oeffnen musst, deshalb macht ifstream den Rest fuer dich 🙂

    Ach ja, und:

    while(!fin.eof())
    {
      fin>>x;
      // ...
    }
    

    funktioniert nicht ganz sauber: du wirst damit einen Schleifendurchgang zuviel haben.... fin.eof() liefert naemlich erst true, nachdem du UEBER DAS ENDE HINAUS gelesen hast. Besser ist ein:

    while(fin >> x)
    {
     // ...
    }
    

    Wo du dann aber das Problem haben wirst, dass die Schleife beim ersten Semikolon abbrechen wird



  • So in etwa wuerde es auch gehen:

    #include <iostream>
    #include <fstream>
    using namespace std;
    int main()
    {
       int x;
       int a[10];
       int i=0;
    
       ifstream fin ("Datei.txt");
    
       while(!fin.eof())
       {
          fin >> x;
    
          // wenn kein Integer ausgelesen wurde (sondern z. B. ein Semikolon),
          // dann wird fin.good() false zurueckgeben...
          // wir ignorieren dann just jenes Zeichen einfach und machen dann
          // wieder normal weiter
          // damit umgehen wir auch das Problem, dass fin.eof() erst "zu spaet" 
          // Alarm schlaegt :)
          if (!fin.good())
          {
             fin.clear(); // fin wieder auf "ok" setzen
             fin.ignore(1); // damit ignorieren wir das "boese" Zeichen
          }
          else
          {
             a[i]=x;
             ++i;  // ++i ist uebrigens besser als i++, aber das ist ein anderes Thema ;-)
          }
       }
       fin.close();
    }
    

    ich hab's jetzt nicht getestet, aber ich denk das funktioniert



  • Hallo,

    du erklärst es 1a, Danke.

    Normalerweise schreibe ich auch int main (), aber es musste halt schnell gehen.
    Was ist eigentlich dieses argc und argv ?
    Ich hab schon mal davon gehört, aber so genau weiß ich das nicht.

    Ich dachte, dass fin nur die "richtigen Zeichen einliest", d.h keine Leerzeichen und Zeilenumbrüche, richtig ?

    Und fin.get() jedes Zeichen oder ?

    Und dass mit meiner Methode die Schleife einen Durchgang zuviel macht ist mir auch augefallen. Er hat 2 mal das selbe Zeichen nacheinander am Ende.

    Hast du vielleicht eine Übersicht über die Methoden, die man mit das Streamobjekt fin ansprechen kann ?

    Tschüss



  • lightning schrieb:

    Was ist eigentlich dieses argc und argv ?
    Ich hab schon mal davon gehört, aber so genau weiß ich das nicht.

    Du hast vielleicht schon mal gesehen, dass Programme mit Parametern aufgerufen werden koennen... wenn ich z. B. in der DOS-Eingabeaufforderung (bzw. der Konsole unter WinXP) folgendes eingebe

    c:\windows\notepad.exe c:\beispiel.txt
    

    dann wird das Notepad gestartet und wird die Datei c:\beispiel.txt oeffnen (sofern die existiert 😉 ). Und woher weiss Notepad das? Eben genau durch argc und argv:

    int main(int argc, char* argv[])
    

    argc ist ein integer, und er enthaelt die Anzahl von Parametern, die du erhalten hast.
    char* argv[] (manchmal auch char** argv geschrieben) ist ein Feld von C-Strings. Vielleicht anfangs bisschen verwirrend, aber das ist nix anderes als ein Array von strings. Da drinnen stehen die Parameter, die dem Programm uebergeben wurden, wobei in argv[0] immer der Name es Programmes drinsteht (muss laut Standard so sein)...

    wenn ich z. B. ein programm "my_program" schreibe, und wie folgt aufrufe:

    my_program.exe a 7
    

    dann ist argc 2 (hab ja 2 Sachen an das Programm mitgegeben), und:

    argv[0] == "my_program"
    argv[1] == "a"
    argv[2] == "7"

    probiers einfach selber mal aus, indem du folgenden Code compilierst und damit ein bischen rumspielst:

    #include <iostream>
    using namespace std;
    
    int main()
    {
        for (int i = 0; i < argc; ++i)
        {
            cout << "argv[" << i << "] == " << argv[i] << '\n';
        }
    
        return 0;
    }
    

    Hoff das war jetzt halbwegs verstaendlich....

    Ich dachte, dass fin nur die "richtigen Zeichen einliest", d.h keine Leerzeichen und Zeilenumbrüche, richtig ?

    fin selber liest gar nichts aus, aber es gibt verschiedene Methoden, um aus fin was rauszulesen, z. B. getline:

    ifstream fin("foo.txt");
    string my_string;
    
    getline(fin, my_string);
    
    // my_string enthaelt nun genau 1 Zeile (und zwar die 1te) von "foo.txt", mit Leerzeichen, aber OHNE Newline
    
    getline(fin, my_string);
    
    // jetzt enthaelt my_string die 2te Zeile der Datei, die fin geoeffnet hat
    

    Es gibt auch getline-Versionen, die mit char*s (also mit C-Strings) arbeiten, gleiches gilt fuer fin.get(). Wenn du fin.get() ohne Argumente aufrufst, dann liest es dir GENAU ein Zeichen aus fin raus... soweit ich mich erinnere auch Newlines (und Leerzeichen)....

    Zum schnellen Nachschlagen empfielt sich www.cppreference.com, aber nix ersetzt ein solides Buch, wo man alles mal erklaert kriegt 🙂



  • lightning schrieb:

    11 12 13 15; 13 23 23 34;
    Ich würde gerne die 4 Zahlen zwischen den Semikoli in ein Feld einlesen ?

    Probier's doch mal mit sscanf():

    #include <stdio.h> // oder <cstdio>
    
    // ...
    
    int a, b, c, d, e, f, g, h;
    if ( sscanf( textzeile, "%d %d %d %d; %d %d %d %d;", &a, &b, &c, &d, &e, &f,
       &g, &h ) == 8 ) { // 8 Zahlen eingelesen
       // a .. d enthaelt die ersten 4 Zahlen
       // e .. h enthaelt die zweiten 4 Zahlen
    }
    


  • Hallo,

    das geht ja nur in diesem Fall.
    Wenn ich 60 Zeichen in eine Datei schreibe, dann müsste ich ja 60 Variablen anlegen und danach noch die Unwichtigen aussortieren.

    Ich hab mal eine Frage.

    Folgende datei:

    name alter wohnort * name alter wohnort * ...

    jetzt würde ich gerne die 3 Elemente immer in ein Listenelement einfügen.
    Also bis zum Sternchen in das erste Listenelement, dann bis zu nächsten in das nächste und so weiter...bis die datei Zuende ist.

    Weiß da jemand Rat ?

    Danke



  • selber denken hat noch niemandem geschadet... im Prinzip der gleiche Code wie in meinem ersten Posting:

    ifstream file("foo.txt");
        string line;
        string::size_type start = 0;
        string::size_type end = 0;
        getline(file, line);
    
        string name;
        string alter;
        string wohnort;
    
        while ((end = line.find_first_of('*', start)) != string::npos)
        {
            istringstream istr(line.substr(start, end - start));
            istr >> name >> alter >> wohnort;
            start = end + 1;
    
            // ..... bearbeiten der aktuellen Daten
        }
    


  • Hallo,

    ich hab den Quellcode noch nicht ganz verstanden.
    Kannst du mir den nochmal kurz erklären ?

    Wäre nett.

    Danke !



  • hmm..... zu allererst: wenn du auch nach dieser Erklaerung nicht alles verstehst, stell sicher, dass du dich mit stringstreams auskennst. istringstreams funktionieren genau so wie cin oder ifstream, ostringstreams genauso wie cout oder ofstream... Nur dass sie ihre Daten nicht von der Konsole holen (bzw. dorthin schreiben), sondern in einen String....
    Dann: schau dir z. B. auf www.cppreference.com mal die Referenz von std::string an, damit du auch weisst, was fuer Methoden so ein string eigentlich hat...

    So, jetzt zum Code:

    ifstream file("foo.txt");
        string line;
    
        // string::size_type ist ein Datentyp fuer Laengenangaben. Ich haett genauso gut auch int nehmen koennen
        string::size_type start = 0;
        string::size_type end = 0;
    
        // liest eine Zeile aus der Datei und speichert sie in line
        getline(file, line);
    
        string name;
        string alter;
        string wohnort;
    
        // line.find_first_of('*', start)... schau mal unter http://www.cppreference.com/cppstring/find_first_of.html
        // er sucht also nach dem Zeichen '*', und startet seine Suche bei line[start]... d.h. start gibt an, ab wo gesucht werden soll
        // end = line.find_first_of('*', start) speichert die Position, wo das '*' gefunden wurde, in end
        // und schliesslich: wenn find_first_of() das Zeichen '*' nicht im String finden kann, wird string::npos zrueckgegeben....
        // wenn also kein '*' nach line[start] mehr gefunden wird, dann bricht die Schleife ab
        while ((end = line.find_first_of('*', start)) != string::npos)
        {
            // ok, hier wird also ein istringstream erstellt... das ist wie gesagt sowas aehnliches wie ein ifstream...
            // nur werden die Daten nicht aus einer Datei gelesen, sondern aus einem string... in diesem Fall aus
            // line.substr(start, end - start). substr() liefert einen Teilstring (einen "substring") aus
            // line, der bei line[start] startet und (end - start) Zeilen lang ist
            // guckst du auch hier: http://www.cppreference.com/cppstring/substr.html
            istringstream istr(line.substr(start, end - start));
    
            // ok, das funktioniert genauso, wie bei einem ifstream oder bei cin:
            // Wenn du da 3 Werte einlesen moechtest, wuerdest du ja auch einfach nur
            // cin >> string1 >> string2 >> string3
            // schreiben. Das hier funktioniert genauso...
            istr >> name >> alter >> wohnort;
    
            // damit beim naechsten Schleifendurchgang nicht wieder das gleiche '*' gefunden wird,
            // sondern das naechste, setzen wir den Startwert fuer die Suche weiter nach rechts
            start = end + 1;
    
            // ..... bearbeiten der aktuellen Daten
        }
    

    So, that's it, ich hoff das war jetzt verstaendlich 🙂



  • Hallo,

    Also wird die gesamte Textzeile in einen string eingelesen und im String werden dann die Operationen gemacht ?
    Was ist wenn die Textdatei einen Zeilenumbruch hat ?
    Kann man folgendermaßen vorgehen:

    ...
    while (getline(file, line))
    {

    while((end = line.find_first_of('*', start)) != string::npos)
    {
    ...}

    }

    Ich lese also immer eine Zeile ein und untersuche die dann !

    Kann das so finktionieren ?



  • ja, so in der Art musst du das sogar machen! 🙂

    getline liesst naehmlich immer nur 1 Zeile raus, d.h. wenn die Datei mehrere Zeilen hat, musst du auch entsprechend oft getline() aufrufen 🙂



  • Hallo,

    ja aber ich muss doch verhindern, dass er jedes Mal die selbe Zeile einliest !
    Kann man irgendwie einen Zeilenumbruch erzwingen ?

    Tschüss



  • while ( getline( file, line ) )
    

    liest ja solange Zeilen ein, bis die Datei zuende ist.



  • while (getline(file, line))

    nein !

    so:

    while (!file.eof())          // liesst die gesamte datei ein
    {
        if(file.eof()){break;};  // verhindert die letzte doppelte zeile
        iStr << string1 << string2 << string3 << endl;
    };
    

    //edit schreibfehler (das übliche halt 😉 )



  • enno-tyrant schrieb:

    while (getline(file, line))

    nein !

    Warum nicht?

    Caipi



  • Caipi schrieb:

    enno-tyrant schrieb:

    while (getline(file, line))

    nein !

    Warum nicht?

    Caipi

    weil es nur eine zeile einliest



  • enno-tyrant schrieb:

    Caipi schrieb:

    enno-tyrant schrieb:

    while (getline(file, line))

    nein !

    Warum nicht?

    Caipi

    weil es nur eine zeile einliest

    Nö. Vergl.

    #include <iostream>
    #include <string>
    #include <fstream>
    using namespace std;
    
    int main()
    {
            ifstream in("test.txt");
            if(in.is_open())
            {
                    string str;
                    while(getline(in, str))
                            cout << str << endl;
            }
            return 0;
    }
    

    (Zumindest bei mir, liest es die ganze Datei ein) 😉

    Caipi


Anmelden zum Antworten