von fstream in structs
-
Hi
Wie kann ich aus einer Datei auslesen und in eine struct schreiben?
struct Weapon { unsigned int id; unsigned short type; unsigned short level; unsigned short strength; unsigned short speed; unsigned short weight; unsigned short range; unsigned int price; std::string name; };File:
# ID Type Level Name Strength Speed Weight Price Range # Swords 1011 0 1 Sword 2 3 2 200 0 1021 0 2 Longsword 3 4 2.3 700 0 1031 0 3 Claymore 5 6 2.5 1200 0 # Axes 1111 1 1 Axe 3 2 2.5 200 0 1121 1 2 Poleaxe 4 3 2.8 700 0 1131 1 3 Battleaxe 6 5 3.2 1200 0Hab schon getline gefunden, aber dann ist ja alles in einem string, wie kann ich das "wortweise", also jeweils bis zum Leerzeichen zerpflücken?
Danke im voraus

-
Oder besser gefragt,
warum gehtvoid test_streams() { ifstream items( "items" ); if( items.is_open() ) { cout << "File open" << endl; while( items.good() ) { cout << "File good" << endl; stringstream sstr; items.get( *sstr.rdbuf() ); std::cout << sstr << std::endl; } } }nicht?
Gibt mir nur pointer Addressen aus..
-
nimm doch einfach den >> operator ...
-
(D)Evil schrieb:
nimm doch einfach den >> operator ...
Hm, tja so einfach gehts..
Aber wie kann ich eine Zeile überspringen bei '#' ?
-
lies einfach mit get ein zeichen am zeilenanfang, und wenns kein # ist, tus mit put zurück in den stream, ansonsten kannste die Zeile mit getline überspringen.
-
Eldoran schrieb:
Hab schon getline gefunden, aber dann ist ja alles in einem string, wie kann ich das "wortweise", also jeweils bis zum Leerzeichen zerpflücken?
getline ist nur dann sinnvoll, wenn das Zeilenende zur Formatierung der Daten notwendig ist. Das ist aber bei Dir so gar nicht der Fall.
Eldoran schrieb:
(D)Evil schrieb:
nimm doch einfach den >> operator ...
Hm, tja so einfach gehts..
Aber wie kann ich eine Zeile überspringen bei '#' ?Genau; der operator>> tut genau das was notwendig ist. Und für das Überspringen der Kommentare sorgt ein sogenannter Manipulator. Alles zusammen sieht so aus:
#include <string> #include <vector> #include <fstream> #include <cmath> // std::floor für korrektes runden #include <iterator> // istream_iterator // -- Kommentar überlesen std::istream& comment( std::istream& in ) { typedef std::istream::traits_type traits_type; in >> std::ws; // ggf. Leerzeichen überlesen for( int m; !traits_type::eq_int_type( m = in.peek(), traits_type::eof() ) && traits_type::to_char_type( m ) == '#'; ) { in.ignore( 9999, traits_type::to_int_type( '\n' ) ); } return in; } struct Weapon { unsigned int id; unsigned short type; unsigned short level; unsigned short strength; unsigned short speed; unsigned short weight; unsigned short range; unsigned int price; std::string name; // -- Weapon einlesen friend std::istream& operator>>( std::istream& in, Weapon& w_ ) { // # ID Type Level Name Strength Speed Weight/10 Price Range Weapon w; double weight_; if( in >> comment >> w.id >> w.type >> w.level >> w.name >> w.strength >> w.speed >> weight_ >> w.price >> w.range ) { w.weight = std::floor( weight_ * 10.0 + 0.5 ); w_ = w; } return in; } }; int main() { using namespace std; ifstream items( "items" ); vector< Weapon > weapons( (istream_iterator< Weapon >( items )), istream_iterator< Weapon >() ); // .. das war's return 0; }Bem.: ich habe mal angenommen, dass das Gewicht mit Faktor 10 in der struct Weapon abgelegt ist.
Gruß
Werner
-
Ui

Danke!
Werd das mal durchgehen, ob ich's kapier.Bem.: ich habe mal angenommen, dass das Gewicht mit Faktor 10 in der struct Weapon abgelegt ist.
Das hab ich vorhin auch gemerkt. Wird dann wohl eher ein double, als ein short werden.
Aber mir stellt sich schon die nöchste Frage.
Mein File sieht im Moment so aus:# Weapons # ID Type Level Name Strength Speed Weight Price Range # Swords 1011 0 1 Sword 2 3 2 200 0 1021 0 2 Longsword 3 4 2.3 700 0 1031 0 3 Claymore 5 6 2.5 1200 0 # Axes 1111 1 1 Axe 3 2 2.5 200 0 1121 1 2 Poleaxe 4 3 2.8 700 0 1131 1 3 Battleaxe 6 5 3.2 1200 0 # Armour # ID Type Level Name Absorb Handicap Weight Price # Helms 2011 0 1 Lether 3 2 1.6 500 2021 0 2 Chain 5 3 2.4 1000 2031 0 3 Massive 8 4 3.2 1500 # Cuirass 2111 1 1 Lether 3 2 0.9 700 2121 1 2 Chain 5 3 1.2 1400 2131 1 3 Massive 8 4 1.8 2100Und es kommen wohl noch weitere Arten von Items dazu.
Die Waffen und Rüstungen sollen aber in verschiedene sets, da ich keine polymorphen Objekte machen will. Hab ich da ne Chance das auf deine elegante Art zu machen? Oder soll ich lieber verschiedene Files machen?Danke nochmal

-
Eldoran schrieb:
Hab ich da ne Chance das auf deine elegante Art zu machen?
im Prinzip schon. Die Frage ist zunächst mal wo in der Datei die Waffen aufhören und die Rüstungen anfangen. Mal angenommen es sind immer genau 6, dann ist es einfach. Du erstellst eine struct Armour nebst operator>> nach dem gleichen Muster wie Weapon und im Hauptprogramm liest Du 6 Waffen und 6 Rüstungen
int main() { using namespace std; vector< Weapon > weapons; vector< Armour > armours; ifstream items( "items" ); Weapon w; for( int n = 0; n<6 && items >> w; ++n ) weapons.push_back( w ); // usw. für die Rüstungen return 0; }Falls Du eine dynamische Anzahl haben möchtest, kannst Du in der Datei entweder die Anzahl davor schreiben (einfach und sicher) oder Dir eine Markierung ausdenken, die das Ende der Waffen angibt und dabei natürlich von einem Kommentar und einer Zahl eindeutig zu unterscheiden ist. Letzteres ist nur zu empfehlen, wenn die Datei von Hand editiert werden soll, weil dann die Angabe der Anzahl redundant und daher fehleranfällig ist. Das Einlesen ist dann aber etwas schwieriger zu programmieren.
Gruß
Werner
-
So, habs nun hinbekommen, dynamisch mit Steuerzeichen.
Wohl nicht sehr elegant, aber es tut was es soll.typedef std::istream::traits_type traits_type; // überspringe Kommentarzeilen "#" std::istream& skip_comment( std::istream& in ) { in >> std::ws; for( traits_type::int_type m; !traits_type::eq_int_type( m = in.peek(), traits_type::eof() ) && traits_type::to_char_type( m ) == '#'; ) { in.ignore( 9999, traits_type::to_int_type( '\n' ) ); } return in; } // überspringe Zeilen mit Steuerungsbefehl "!" std::istream& skip_command( std::istream& in ) { in >> std::ws; for( traits_type::int_type m; !traits_type::eq_int_type( m = in.peek(), traits_type::eof() ) && traits_type::to_char_type( m ) == '!'; ) { in.ignore( 9999, traits_type::to_int_type( '\n' ) ); } return in; } // lade Werte aus Datei void BattleSystem::load_values() { enum Section { NONE = 0, WEAPON = 1, ARMOR = 2 }; Section section = NONE; ifstream items( "items" ); if( items.is_open() ) { while( items.good() ) { if( '!' == traits_type::to_char_type( items.peek() ) ) { section = static_cast<Section>(section + 1); items >> skip_command; // Nach Bearbeitung des Befehls Position weiterschieben } switch( section ) { case WEAPON: { Weapon weapon; items >> weapon; // Entsprechende operator>> überladung s.o. m_weapons.insert( weapon ); break; } case ARMOR: { Armor armor; items >> armor; // dito m_armors.insert( armor ); break; } default: break; } items.ignore(); // ohne dies lädt er nur die Waffen :confused: } } items.close(); }Und das File sieht so aus:
! #Weapons # ID Type Level Name Strength Speed Weight Price Range # Swords 1011 0 1 Sword 2 3 2 200 0 1021 0 2 Longsword 3 4 2.3 700 0 1031 0 3 Claymore 5 6 2.5 1200 0 # Axes 1111 1 1 Axe 3 2 2.5 200 0 1121 1 2 Poleaxe 4 3 2.8 700 0 1131 1 3 Battleaxe 6 5 3.2 1200 0 ! #Armor# # ID Type Level Name Absorb Handicap Weight Price # Helms 2011 0 1 Lether 3 2 1.6 500 2021 0 2 Chain 5 3 2.4 1000 2031 0 3 Massive 8 4 3.2 1500 # Cuirass 2111 1 1 Lether 3 2 0.9 700 2121 1 2 Chain 5 3 1.2 1400 2131 1 3 Massive 8 4 1.8 2100 ! #EOFDanke nochmal vielmals euch allen, vor allem Werner

Gruss