Aus .txt Datei lesen



  • Hallo, ich fang gerade an mich mit Datein zu beschäftigen, hier mal ein Beispiel. Ich hab eine Datei namens "Hans.txt" die sich in "D:\" befindet.
    In der Datei steht "Hans Werner Olm".

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int main()
    {
        ifstream data("D:\\Hans.txt");
        char input[16];
        data.read(input,15);
        input[15]='\0'; // <-- !!!
        cout << input << endl;
    
        return 0;
    }
    

    Wie man sieht hab ich das Nullzeichen selbst angefügt, muss man das immer selber anfügen, weil das is ja schon n bissel aufwendig, oder gibts vll. schon irgend eine Funktion die das für einene übernimmt, oder muss ich mir die einfach selber schreiben?
    Dankeschön schon mal im Voraus.



  • die read-methode von ifstream ist für binärdaten gedacht. Wenn du Text auslesen willst kann du das mit Operator >> machen (wie bei cin) oder mit std::getline. Und speicher das ganze in std::string und nicht in char*

    Gruß, Maxi



  • Nächste Frage!
    Wie kann ich feststellen wieviel Zeichen eine Datei enthält?
    Bzw. mit welcher Funktione kann ich den Lesezeiger an das Ende der Datei positionieren.
    Dankeschön schon mal im Voraus.



  • Bzw. mit welcher Funktione kann ich den Lesezeiger an das Ende der Datei positionieren.

    std::ifstream::seekg(0, std::ios::end) müsste es sein ...



  • Ah thx (D)Evil, funktioniert prima.
    Aber für was ist die "0", warum geht da nicht --> std::ifstream::seekg(std::ios::end) [da wird der Lesezeiger dann beo mir an 2ter Stelle positioniert ]
    Was macht die "0"? Soll das heißen von anfang an? Aber der Lesezeiger ist doch sowieso schon auf Position 0 am anfang.... blick ich no net so ganz für was das argument sein soll.
    Dankeschön schon mal im Voraus.



  • hmm du gibst damit an wie weit er vom Punkt std::ios::end seeken soll ... kannst ja auch von std::ios::cur um 10 nach vorne seeken udg.



  • Um mir die Arbeit zu erleicht hab ich mir eine Funktion "file_input" geschrieben die mir die Arbeit ein wenig erleichtert. Dann gibt es noch die Funktion "file_volume", von welcher "file_input" gebrauch nimmt.

    #include <iostream>
    #include <fstream>
    using namespace std;
    
    int file_volume(char *input);
    void file_input(string &file, char *input);
    
    int main()
    {
        string a;
        file_input(a,"D:\\Hans.txt");
        cout << a << endl;
    
        return 0;
    }
    
    //Schreib in einen string den Inhalt einer Datei
    void file_input(string &file, char *input)
    {
        int volume;
        //überprüfen ob file_volume kontak mit gültiger Datei hatte
        if(file_volume(input)==-1)
        {
            file="-1"; //FALSE
            return;
        }
        else
        {
            volume=file_volume(input);
        }
        char *temp=new char(volume+1);
        ifstream data(input);
        //überprüfen ob kontakt mit gültiger datei hergestellt ist
        if(!data.is_open())
        {
            file="-1"; //FALSE
            data.close();
            return;
        }
        data.read(temp,file_volume(input));
        temp[volume]='\0';
        data.close();
        file=temp;
        delete temp;
    }
    
    //Gibt die Anzahl der Zeichen zurück die eine Datei beinhaltet
    inline int file_volume(char *input)
    {
        int temp;
        ifstream data(input);
        if(!data.is_open())
        {
            return -1; //FALSE
        }
        data.seekg(0,ios::end);
        temp=data.tellg();
        data.close();
        return temp;
    }
    

    AUSGABE:

    Hans Werner Olm

    1. Was würdet ihr alles an meinem Code zu bemängeln bzw. zu verbessern haben? Tipps...
    2. Findet ihr das "inline" in Zeile 48 sinnvoll? Bringt das überhaupt was oder soll ichs weglassen?
    3. Was sagt ihr zu meinen Überprüfungen mit "is_open"? Würdet ihr das auch so machen? Und wie würdet ihr das bei der Funktion "file_input" machen, weil wenn es nicht geklappt hat dann wird in den string ja immer "-1" geschrieben, was ist aber bitte wenn in der Datei aus der "file_input" liest wirklich mal nur "-1" drinstehen sollte? Mhhh? Wie könnte ich das den anderst machen=

    Dankeschön schon mal im Voraus.



  • öhm das ist nicht gerade cream de la cream

    inline std::size_t file_volume(std::ifstream& strm)
    {
    	if (!strm)
    		return 0;
    
    	std::streampos cur = strm.tellg();
    	strm.seekg(0, std::ios::beg);
    	std::streampos beg = strm.tellg();
    	strm.seekg(0, std::ios::end);
    	std::size_t size = strm.tellg() - beg;
    	strm.seekg(cur, std::ios::beg);
    	return size;
    }
    
    bool file_input(const std::string& file_name, std::string& input_string)
    {
    	input_string = "";
    	std::ifstream file_stream(file_name.c_str(), std::ios::binary);
    	if (!file_stream)
    		return false;
    
    	std::size_t file_size = file_volumn(file_stream);
    	if (file_size == 0)
    		return true;
    
    	char* tmp = new char[file_size];
    	file_stream.read(tmp, file_size);
        input_string = tmp;
    	delete [] tmp;
    	return true;
    }
    

    ... somit öffnest du nur 1 mal die Datei ... rufst nur 1x file_volumn auf ... gibst den ARRAY tmp KORREKT frei usw ^^



  • (D)Evil schrieb:

    input_string = "";
    

    ich würde ein input_string.clear(); vorziehen



  • Stromberg ne Frage: Von welcher Quelle lernst du eigentlich C++ ???
    Man sieht dich ja öfters hier, mit "komischen" Fragen. Ich glaube du brauchst nen gutes Buch um den roten Faden zu finden ...



  • Hmm, ne Textdatei einzulesen ist doch nen Einzeiler. Wieso der ganze Aufwand?

    string read_file(string const& fname)
    {
        return dynamic_cast<stringstream*>(&(stringstream() << ifstream(fname.c_str()).rdbuf()))->str();
    }
    


  • hmm hab nur seine Funktionen verbessert bzw. korrigiert.



  • Hab schon soviele Bücher aber die bringen alle nix, oder ich bin in irgend nem kapitel hängen geblieben...weil wirklich langweilig wurde, eigentlich hab ich mir jetzt vorgenommen, noch die ganzen String Funktionen zu lernen...weil ich mich da noch nicht auskenne, also z.B. wie man alles in Großbuchstaben umwandelt....
    Und danach wollte ich eigentlich das Buch "Die C++ Standardbibliothek" durchmachen, das hab ich mir vor einiger Zeit gekauft und es liegt halt in meinem Regal rum...ich hoff wenn ich mit dem fertig bin hab ich bisschen mehr Wissen.
    Und das mit den Datein mach ich eigentlich gerade nur um mal n kleines bisschen "action" reinzubringen, weil ich mach das jetzt echt schon lange (6 Moante sind untertrieben) komm aber irgendwie nicht auf nen grünen Zweig....weil ich wills zwar können aber irgendwie stell ich mich so an oder ich weiß nicht....und mir fällt eigentlch auch gerade gar nicht mehr ein was ich programmieren soll, weil alles ist so bock langweilig wenn man immer wieder das gleiche in der blöden schwarzen Konsole macht. Aber so "macht's mich schon an" wenn ich hier andere Beiträge lese...und dann denk ich mir wieder Augen zu und durch irgendwann wirst auchs du blicken --> auch ein blindes Huhn findet mal ein Korn.
    So jetzt hab ich mal hier rumgelabbert und mein Herz ausgeschüttet ich mach trotzdem weiter mit der Sprache!!!
    Ich mein so schwierig kann C++ doch gar nicht sein? Ihr könnt es doch auch alle? Mh?
    Vll. liegts bei mir auch daran das ich mir von anfang an das falsche Lehrbuch gekauft habe --> Jetzt lerne ich C++?
    Mh ach ich weiß auch nicht, und so schnell gebe ich noch nicht auf und ihr müsst euch weiter mit meinen komischen Fragen rumärgern.
    MfG
    Stromberg



  • Stromberg schrieb:

    Hab schon soviele Bücher aber die bringen alle nix, oder ich bin in irgend nem kapitel hängen geblieben...weil wirklich langweilig wurde, eigentlich hab ich mir jetzt vorgenommen, noch die ganzen String Funktionen zu lernen...weil ich mich da noch nicht auskenne, also z.B. wie man alles in Großbuchstaben umwandelt....
    Und danach wollte ich eigentlich das Buch "Die C++ Standardbibliothek" durchmachen, das hab ich mir vor einiger Zeit gekauft und es liegt halt in meinem Regal rum...ich hoff wenn ich mit dem fertig bin hab ich bisschen mehr Wissen.
    Und das mit den Datein mach ich eigentlich gerade nur um mal n kleines bisschen "action" reinzubringen, weil ich mach das jetzt echt schon lange (6 Moante sind untertrieben) komm aber irgendwie nicht auf nen grünen Zweig....weil ich wills zwar können aber irgendwie stell ich mich so an oder ich weiß nicht....und mir fällt eigentlch auch gerade gar nicht mehr ein was ich programmieren soll, weil alles ist so bock langweilig wenn man immer wieder das gleiche in der blöden schwarzen Konsole macht. Aber so "macht's mich schon an" wenn ich hier andere Beiträge lese...und dann denk ich mir wieder Augen zu und durch irgendwann wirst auchs du blicken --> auch ein blindes Huhn findet mal ein Korn.
    So jetzt hab ich mal hier rumgelabbert und mein Herz ausgeschüttet ich mach trotzdem weiter mit der Sprache!!!
    Ich mein so schwierig kann C++ doch gar nicht sein? Ihr könnt es doch auch alle? Mh?
    Vll. liegts bei mir auch daran das ich mir von anfang an das falsche Lehrbuch gekauft habe --> Jetzt lerne ich C++?
    Mh ach ich weiß auch nicht, und so schnell gebe ich noch nicht auf und ihr müsst euch weiter mit meinen komischen Fragen rumärgern.
    MfG
    Stromberg

    Hmmm, hört sich schon frustrierend an. Schon deine erste Frage hier, deutete darauf hin, das du irgendwas falsch lernst.

    In jedem vernüftigen Tutorial, würdest du direkt lernen das ein getline(file,string) reichen würde um deinen "Hans Werner Olm" zu bekommen.

    Oder einfach dreimal, genau wie bei cin, >> benutzen:

    //umständlich, soll aber nur verdeutlichen
    string a,b,c,name;
    file >> a,b,c;
    name = a + " " + b + " " + c;
    /*
    Wenn du willst das jmd dir über die Konsole "Hans Werner Olm" eingeben soll,
    dann würdest du es ja auch so machen:
     file >> a,b,c;  
    Du musst cin und die ifstream gleich sehen, nur die Quelle von der die Daten bezogen werden ist unterschiedlich. Einmal Tastatur, einmal Datei ... 
    */
    

    Wesentlich einfach natürlich das:

    string name = "";
    getline(file,name);
    

    Das alles hat dir ja Maxi schon am Anfang vorgeschlagen.

    So einfach kann das sein 😉

    Wenn du jetzt eine ganze Datei einlesen willst, denkst du weiter:

    //Mit getline lese ich mir ja eine Zeile aus
    //Also muss ich jetzt, solange getline Machen bis es keine Zeilen mehr gibt
    
    ifstream file("datei.txt");
    if(!file) // return oder sonstwas
    //oder if(file) schreiben und in { } mit der Datei arbeiten
    /*
        if(file)
        {
           arbeiten mit datei
        }
    
    */
    
    // Nun Zeilen auslesen, bis zum EOF
    string fileText = ""; // Alles immer schön initalisieren 
    while(!file.eof())
    {
        string temp = "";
        getline(file,temp);
        fileText += temp + "\n";
    }
    // gesamter Dateiinhalt nun in fileText;
    

    Nun spielen wir ja hier mit C++ und das alles ist noch nicht ganz so sicher.
    Das Problem ist das file.eof() gibt dir nur EOF zurück, wenn es mal eingelesen wurde. Das heißt eof() weiß nicht das gleich EOF kommen könnte.
    Demnach könnte unerwartetes passieren und wir EOF einlesen:

    while(!file.eof())
    {
        string temp = "";
        getline(file,temp);
        // falls wir EOF einlesen sollten, dann raus aus schleife
        if(file.eof()) break;
        fileText += temp + "\n";
    }
    

    Nun ist gut, aber es geht noch schöner:

    string temp = "";
    while(getline(file,temp))
    {
        fileText += temp + "\n";
    }
    // getline liefert den stream wieder zurück
    // also sieht das nach getline so aus: while(file)
    // Dh wenn file ok ist läuft die Schleife und das ist es wenn zB nicht sowas wie EOF kommt
    

    Natürlich gibt es noch Sachen wie copy und iteratoren die alles auf eine Zeile bringen:
    http://c-plusplus.net/forum/viewtopic-var-p-is-1280471.html#1280471
    Aber lass das erst mal und arbeite normal um alles zu verstehen.

    Zu der Geschichte EOF gibts hier was schönes:
    http://fara.cs.uni-potsdam.de/~kaufmann/?page=GenCppFaqs&faq=eof#Answ
    Zudem noch jede Menge anderer nützlicher Tipps.

    So "Der Anschlag" läuft, muss los 🙂



  • Also vielen Danke erst mal an dich KasF für deine lange Erklärung.
    Ich hab mich jetzt nochmal genau hingesetzt, und das von (D)Evil und von dir aufmerksam durchgelesn, bisschen rumprobiert, wieder euren Code angeschaut.... und ich bilde mir ein es nun verstanden zu haben. Das hier wäre mein Code:

    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    int file_volume(ifstream &stream);
    bool file_input(string &file,const string input) ;
    
    int main()
    {
        string buffer;
        file_input(buffer,"D:\\Hans.txt");
        cout << buffer << endl;
    
        return 0;
    }
    
    int file_volume(ifstream &stream)
    {
        int temp;
        if(stream)
        {
            stream.seekg(ios::beg,ios::end);
            temp=stream.tellg();
            stream.seekg(ios::beg);
        }
        else
        {
            return 0;
        }
    }
    
    bool file_input(string &file,const string input)
    {
        ifstream data(input.c_str());
        string temp;
        while(getline(data,temp))
        {
            file=file+temp+"\n";
        }
        if(file.length()!=file_volume(data))
        {
            data.close();
            return 0;
        }
        data.close();
        return 1;
    }
    

    Jetzt is es aber doch ganz in Ordnung, is ja so ähnlich wie euer Code?
    Das mit dem "while(getline(data,temp))...." was du mir erklärt hast KasF, ist natürlich schon n kleiner unterschied zu dem was ich gemacht habe 😃
    Dankeschön schon mal im Voraus.



  • hmm ...

    stream.seekg(ios::beg,ios::end);
    

    ... was soll das sein? Guck dir mal die genaue Deklaration von seekg an ... http://www.cppreference.com/cppio/seekg.html

    int file_volume(ifstream &stream) // warum int? kann doch nur positiv lang sein ;) => std::size_t (meist das selbe wie unsigned int)
    {
        int temp; // warum hier schon anlegen? Wird doch nur genutzt wenn stream geöffnet ist ...
        if(stream)
        {
            stream.seekg(ios::beg,ios::end); // s. o.
            temp=stream.tellg(); // hmm tellg sollte aber std::streampos und nicht int zurückgeben. 
            stream.seekg(ios::beg); // Und wenn du vorher nicht am Anfang der Datei warst?
        }
        else
        {
            return 0;
        }
    }
    

    ...

    bool file_input(string &file,const string input)
    {
        ifstream data(input.c_str()); 
        // und was ist wenn du die Datei nicht öffnen konntest? (!data)
        // Was ist wenn in file schon was drin steht?
        string temp;
        while(getline(data,temp))
        {
            file=file+temp+"\n";
        }
        if(file.length()!=file_volume(data)) // wofür?!
        {
            data.close(); // unnötig ...
            return 0;
        }
        data.close(); // unnötig ...
        return 1;
    }
    


  • Zudem von (D)Evil noch. file_volume vergisst einmal was zurückzugeben 😉



  • Joa, so gut isses anscheinend noch nicht, aber es ist besser als mein anfang.
    Zu dem hier noch:

    if(file.length()!=file_volume(data)) // wofür?! 
        { 
            data.close(); // unnötig ... 
            return 0; 
        } 
        data.close(); // unnötig ... 
        return 1;
    

    Ich will doch 0 zurückgeben wenn es fehlgeschlagen hat und 1 zurückgeben wenn es funktioniert hat? Aber vll. ist das von mir n bissel komisch umgesetzt worden?

    Was ist wenn in file schon was drin steht?

    Das ist doch egal oder? Dann wird das halt einfach überschrieben und es steht halt was neus drin?
    Dakeschön schon mal im Voraus.



  • #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    //int file_volume(ifstream &stream);
    bool file_input(string &file,const string input) ;
    
    int main()
    {
        string buffer;
        file_input(buffer,"D:\\Hans.txt");
        cout << buffer << endl;
    
        return 0;
    }
    
    /*size_t file_volume(ifstream &stream)
    {
        if(stream)
        {
            int temp;
            stream.seekg(ios::beg,ios::end);
            temp=stream.tellg();
            stream.seekg(ios::beg);
        }
        else
        {
            return -1;
        }
    }*/
    
    bool file_input(string &file,const string input)
    {
        ifstream data(input.c_str());
        if(data.is_open())
        {
            string temp;
            while(getline(data,temp))
            {
                file=file+temp+"\n";
            }
            data.close();
            return 1;
        }
        return 0;
    }
    

    Wie is es so? Habs nochmal überdacht!
    eigentlich brauch ich jetzt die "file_volume" Funktion doch nicht mehr oder? Äh und was passt an meiner "file_volume" den nicht, die funktiuoniert doch prima? Wie funktioniert das den sonst mit dem "seekg"? Ich kann mit dem Link irgendwie nicht viel anfangen, da stand nicht grad viel drin...?
    Dankeschön schon mal im Voraus.



  • Stromberg schrieb:

    bool file_input(string &file,const string input)
    {
        // …
            return 1;
        }
        return 0;
    }
    

    Was soll eigentlich der Unsinn, '0' und '1' statt 'false' und 'true' zu benutzen?
    Und außerdem halte ich die Lösung mit 'getline' für absoluten Overkill, wenn es doch viel einfacher über einen Stream geht. Wir wollen schließlich keine Zeilen einlesen sondern die gesamte Datei. Wie ich bereits gepostet habe, geht das mit *einer Zeile*!



  • Ah du hast da ja was gepostet, hab ich gar nicht gelesen:

    string read_file(string const& fname) 
    { 
        return dynamic_cast<stringstream*>(&(stringstream() << ifstream(fname.c_str()).rdbuf()))->str(); 
    }
    

    Ah mit einer Zeile ist das ja noch einfacher....bloß muss ich mir das erst noch ma genau anschauen, weil auf die schnell blick ich das jetzt nicht, und was ist den bite ein "dynamic_cast"?
    Und zu dem TRUE und FALSE noch, also ich hab irgendwo auf so einer Internetseite mal gelesen das es gar nicht gut sein soll "TRUE" und "FALSE" zu verwenden, des hat da irgendjemand gesagt..(vll. find ichs wieder).
    Aber eigentlich benutze ich auch immer TRUE und FALSE...weiß eiegtnlich auch nicht warum ich jetzt 1 und 0 genommen habe.
    Und was meinst du mit Overkill? Meinst damit das es zu lange dauert?
    Dankeschön schon mal im Voraus.


Anmelden zum Antworten