Datei Manipulation



  • Hallo Leute.
    Ich bin eigentlich noch ziemlich neu im Thema C++ und habe so einige Fragen.
    Ich habe mehrfach im Internet gesucht aber teilweise nichts gefunden und vorallem noch weniger verstanden.
    Deshalb richte ich mich nun an euch. Habt erbarmen 😉
    Also...

    Ich möchte eine verkettete Liste in eine Datei "bauteilliste.txt" speichern.
    Dies klappt mit dem noch unvollständigen Code wunderbar:

    void save(bauteil *a){
    	ofstream datei;
    	datei.open("bauteilliste.txt");
    	datei << "Bauteil\tLieferant\tPreis\tAnzahl\n";
    	if(a==0) cout << "----Keine Bauteile eingetragen----\n\n";
    	while(a!=0){
    		datei << a->name << "\t" << a->lieferant << "\t\t" << a->preis << "\t" << a->anzahl << endl;
    		a=a->next;
    	};
    	datei.close();
    }
    

    Die Datei hat also volgendes Format:

    Bauteil Lieferand Preis Anzahl
    part1 ti 5.77 567
    part2 ti 4.55 12

    Nun möchte ich mit meinem Programm auch die Datei auslesen und alle Bauteile als verkettete Liste aufnehmen.
    Ich muss dazu sagen ich bin absolut unerfahren mit der Dateimanipulation, zu dem weiß ich nicht wie ich genau vorgehen soll.
    Zunächst einmal muss ich ja die erste Zeile überspringen, wie geht das?
    dann muss ich alle zeichen bis zum \t lesen, das ist dann der bauteilname also
    für meine struct

    struct bauteil{
    	char name[10];
    	char lieferant[10];
    	double preis;
    	int anzahl;
    	bauteil *next;
    };
    

    gilt dann ja:

    bauteil *neu = new bauteil;
    neu->name = ...tja da muss ja nur der name hin...
    

    dann muss ich ja den lieferanten auslesen und in neu->lieferant speichern usw..

    ich weiß leider nicht mehr weiter.
    danke erstmal

    Gruß Timo



  • normalerweise würde ich dir jetzt die klassen

    std::list (für die verkettete liste #include <list>)
    std::string (für das einlesen einer zeile #include <string>)
    std::stringstream (für das umwandlen einer zeile in zahlen #include <sstream>)

    nahelegen

    aber da du das programm schon mit der liste aufgebaut hast, müssen wir das manuell machen 🙂

    der code ist nicht getestet!

    also wir brauchen einen puffer um die zeilen abzuspeichern. 256 zeichen sollten reichen

    char buffer[256];
    

    dann nehmen wir ifstream

    ifstream datei("bauteilliste.txt");
    
    //dann lesen wir eine zeile ein und suchen nach dem '\n'
    
    while (1)
        if (datei.get() == '\n')
            break;
    

    so und jetzt alles in die liste!

    bauteil *anker = 0;
    while (1)
    {
        bauteil *temp = new bauteil;
        datei >> temp->name;  // achtung pufferüberlauf
        datei.get() // um das leerzeichen zu überspringen, weiß nicht
                    // ob das automatisch funktioniert
        datei >> temp->lieferant;
        datei.get();
        datei >> temp->preis;
        datei.get();
        datei >> temp->anzahl;
        datei.get() // das '\n' damit wir in der nächsten zeile sind
    
        temp->next = anker;
        anker = temp;
    
        if (datei.eof())  // um das ende zu finden
            break;    
    }
    

    dann hast du in "Anker" die ganze liste

    nochmals: der code ist nicht getestet und komplizierter als die oben genannten klassen, aber er erklärt wie mans machen kann

    mfg helferlein



  • EDIT: das

    char buffer[256];
    

    muss weg, das gehört da nicht hin (überbleibsel der ersten idee)


  • Administrator

    Hallo ntfs2008,

    Du solltest zuerst einmal char-Arrays wegkommen und auf std::string umstellen, das erleichtert dir eine Menge Arbeit.
    Für Listen gibt es zudem auch bereits vorgefertigte Klassen in der C++ Standardbibliothek, zum Beispiel std::list .

    Durch das benutzen von Textstreams, kannst du die Sache sehr leicht gestalten, da diese Leerzeichen beim einlesen auslassen.

    Zudem empfehle ich persönlich von struct s wegzukommen und auf class mit private zu setzen. Obwohl man dann ein paar Setter und Getter schreiben muss, so kann dies extrem praktisch für spätere Erweiterungen oder Debugging, bzw. Logging sein.

    Und nun das ganze in etwas Code:

    #include <list>
    #include <string>
    #include <fstream>
    #include <iostream>
    #include <iterator>
    #include <algorithm>
    
    class Bauteile
    {
      // Attributes //
    private:
      std::string m_name;
      std::string m_lieferant;
      double m_preis;
    
      unsigned int m_menge;
    
      // Constructors //
    public:
      Bauteile()
        : m_name()
        , m_lieferant()
        , m_preis(0.0)
        , m_menge(0)
      {
      }
    
      Bauteile(std::string const& name,
              std::string const& lieferant,
              double preis,
              unsigned int menge)
        : m_name(name)
        , m_lieferant(lieferant)
        , m_preis(preis)
        , m_menge(menge)
      {
      }
    
      // Methods //
    public:
      std::string const& get_name() const { return m_name; };
      void set_name(std::string const& name) { m_name = name; };
    
      std::string const& get_lieferant() const { return m_lieferant; };
      void set_lieferant(std::string const& lieferant) { m_lieferant = lieferant; };
    
      double get_preis() const { return m_preis; };
      void set_preis(double preis) { m_preis = preis; };
    
      unsigned int get_menge() const { return m_menge; };
      void set_menge(unsigned int menge) { m_menge = menge; };
    
      friend std::istream& operator >>(std::istream&, Bauteile&);
    };
    
    std::ostream& operator <<(std::ostream& output, Bauteile const& bauteile)
    {
      output << bauteile.get_name() << '\t' << bauteile.get_lieferant() << '\t'
             << bauteile.get_preis() << '\t' << bauteile.get_menge();
    
      return output;
    }
    
    std::istream& operator >>(std::istream& input, Bauteile& bauteile)
    {
      input >> bauteile.m_name >> bauteile.m_lieferant
            >> bauteile.m_preis >> bauteile.m_menge;
    
      return input;
    }
    
    typedef std::list<Bauteile> BauteileListe_t;
    
    void save(BauteileListe_t const& liste, std::string const& fileName)
    {
      std::ofstream file(fileName.c_str());
    
      std::copy(liste.begin(), liste.end(), std::ostream_iterator<Bauteile>(file, "\n"));
    
      file.close();
    }
    
    void read(BauteileListe_t& liste, std::string const& fileName)
    {
      std::ifstream file(fileName.c_str());
    
      std::copy(std::istream_iterator<Bauteile>(file), std::istream_iterator<Bauteile>(), std::back_inserter(liste));
    
      file.close();
    }
    
    void wait_close()
    {
      std::cout << std::endl << "Press Enter to exit..." << std::endl;
    
      std::cin.ignore(std::cin.rdbuf()->in_avail());
      std::cin.clear();
      std::cin.get();
    }
    
    int main()
    {
      BauteileListe_t bauteileListe;
    
      bauteileListe.push_back(Bauteile("a", "lieferant", 40.32, 200));
      // usw.
    
      save(bauteileListe, "./test.txt");
    
      bauteileListe.clear();
    
      load(bauteileListe, "./test.txt");
    
      wait_close();
    
      return 0;
    }
    

    C++ Standardbibliothek Referenz:
    http://www.cplusplus.com/reference/

    *aus einem Rausch erwacht*
    ... Irgendwie habe ich das Gefühl, dass ich es grad etwas übertrieben habe ...

    😃

    Grüssli



  • ganz ehrlich.. du hast dir zwar viel mühe gegeben und das macht so bestimmt auch sehr viel sinn und ist in sich schlüssig, aber es hilft mir wirklich wenig.
    zumal mir ganz grundlegende sachen fehlen möchte ich lieber ersteinmal das was ich habe passend erweitern.
    aber trotzdem vielen dank



  • ja ich weiß das ist irgendwie ganz blöd nem anfänger zu helfen, weil die wollen es ja meist nicht so wie man es machen sollte. 😉 aber gibt es da ne möglichkeit wie ich, sagen wir mal, einfacher zum ziel komme?
    gruß


  • Administrator

    Gut, etwas einfacher ...
    Mach aus:

    struct bauteil{
        char name[10];
        char lieferant[10];
        double preis;
        int anzahl;
        bauteil *next;
    };
    

    das folgende:

    struct bauteil{
        std::string name;
        std::string lieferant;
        double preis;
        int anzahl;
    };
    

    Dazu musst du oben allerdings den folgenden Header reinnehmen:
    #include <string>

    Die save -Funktion veränderst du so:

    void save(std::list<bauteil> const& liste)
    {
      ofstream datei;
      datei.open("bauteilliste.txt");
      datei << "Bauteil\tLieferant\tPreis\tAnzahl\n";
      if(a==0) cout << "----Keine Bauteile eingetragen----\n\n";
    
      std::list<bauteil>::const_iterator iter = liste.begin();
      std::list<bauteil>::const_iterator end = liste.end();
    
      while(iter != end){
          datei << iter->name << "\t" << iter->lieferant << "\t\t" << iter->preis << "\t" << iter->anzahl << endl;
          ++iter;
      };
      datei.close();
    }
    

    Dazu musst du oben den folgenden Header includieren:
    #include <list>

    Und nun zur load -Funktion:

    void load(std::list<bauteil>& liste)
    {
      ifstream datei;
      datei.open("bauteilliste.txt");
    
      // um diese linie zu überspringen: datei << "Bauteil\tLieferant\tPreis\tAnzahl\n";
      std::string line;
      std::getline(std::cin, line);
    
      // Nun die Datensätze auslesen. Leerzeichen " \r\n\t" werden automatisch ignoriert.
      bauteile b;
      while(datei >> b.name >> b.lieferant >> b.preis >> b.anzahl)
      {
        liste.push_back(b);
      }
    
      // Der Stream wird ungültig, wenn das Ende erreicht wird und dadurch bricht
      // die While-Schleife ab.
    }
    

    Ist es so besser?

    Grüssli



  • jo das hilft mir schon weiter, obwohl ich einige dinge noch nicht vorher gesehen habe, aber das ist ja nicht verwunderlich.
    echt heftig wie einige leute hier ausm stehgreif mal eben was da hin tippen, und ich sitze hier stunden über stunden 😞
    nur benötige ich weiterhin verkettete listen. das kann ich doch einfach so stehen lassen oder?


  • Administrator

    ntfs2008 schrieb:

    jo das hilft mir schon weiter, obwohl ich einige dinge noch nicht vorher gesehen habe, aber das ist ja nicht verwunderlich.

    Immer fragen, falls etwas nicht klar ist 😉

    ntfs2008 schrieb:

    echt heftig wie einige leute hier ausm stehgreif mal eben was da hin tippen, und ich sitze hier stunden über stunden 😞

    Mit etwas Übung wird das schon 🙂

    ntfs2008 schrieb:

    nur benötige ich weiterhin verkettete listen. das kann ich doch einfach so stehen lassen oder?

    std::list ist eine verkettete Liste. Die wird vom Standard gleich mitgeliefert. Sie ist sogar doppelt verkettet.

    Ich hatte schon vorhin den Link hingeschrieben:
    http://www.cplusplus.com/reference/

    Dort ist ein grosser Teil der Standardbibliothek dokumentiert.

    Wie bist du eigentlich grad am C++ lernen? Hast du ein gutes Tutorial oder Buch? Ein gutes C++ Einsteigerbuch, welches oft empfohlen wird, ist "C++ Primer":
    C++ Primer | ISBN: 9783827326126

    Grüssli



  • naja ehrlich gesagt habe ich z.z. nur das internet.
    im grunde hatten wir das alles mal in der vorlesung, aber leider hatten wir einen ziemlich schlechten prof, sodass im grunde keiner was verstanden hat.
    nun beginnt bald der nächste kurs für uns und dafür mache ich gerade die aufgaben.



  • ntfs2008 schrieb:

    naja ehrlich gesagt habe ich z.z. nur das internet.
    im grunde hatten wir das alles mal in der vorlesung, aber leider hatten wir einen ziemlich schlechten prof, sodass im grunde keiner was verstanden hat.
    nun beginnt bald der nächste kurs für uns und dafür mache ich gerade die aufgaben.

    Wenn du einen schlechten Professor hast, ist das zwar blöd, aber dein Problem. So hart das klingt, aber da musst du halt selber nachhelfen und die ein paar Bücher zu tun. Glaub mir Bücher helfen Wunder. 😉 - Internet benutze ich lediglich als Referenz, wenn ich gerade was nachschauen muss, aber zum lernen finde ich Tutorials usw. einfach nicht geeignet.
    Den Vorteil, den ich Büchern gebe ist, dass man zu einem Thema alles erfährt und nicht nur das, was man gerade braucht. Somit hast du auch Sachen, die dich gerade nicht interessieren im Kopf und kannst gerade mal eben das Buch rauskramen und den Teil nachlesen. Das finde ich besser, als alles durch suchen und nachahmen zum laufen zu bringen.



  • Da hast du absolut recht. Schließlich muss jeder alleine für sich lernen.
    leider fehlt mir, man glaubt es kaum, während dem Semester die Zeit mich wirklich in Ruhe damit zu beschäftigen. "Leider" muss man dies aber, wie ich bereits gemerkt habe.
    Naja ich nehme übernächste Woche noch an einem Vorbereitungskurs teil, wo wir diese Aufgaben nocheinmal besprechen. Bisher habe ich fast alles gelöst, was mich einwenig zufrieden stimmt, vorallem dann, wenn ich die anderen sehe ^^.
    Leider habe ich für die Aufgaben sehr viel Zeit und Hilfe benötigt, aber ich hatte/habe einfach große Defizite.
    Ich werde weiterhin noch gut durcharbeiten, dann solls wohl klappen.

    Danke Timo


Anmelden zum Antworten