Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

AwesomeChick

Frischling

  • »AwesomeChick« ist der Autor dieses Themas

Beiträge: 13

Wohnort: Bayern

Beruf: Programmierer

  • Private Nachricht senden

1

04.03.2010, 16:37

binary read/write

hi, ich habe folgendes problem: ich will eine klasse von einer datei auslesen,
einen wert verändern, doch es klapp nicht.
Das 'erste schreiben' isti auskommentiert, da ich die datei ja nicht
jedesmal beim start überschreiben will.
auslesen klappt alles, habe ich schon mit dem debugger geprüft, nur
das überschreiben klappt nicht, so wie ich will.
Hier mal der quellcode

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <iostream>
using namespace std;
#include <fstream>
#include <cstring>
#include <iomanip>
#include <direct.h>
#include "fs_class.h"


#define Pfad "C:\\cpp\\fs_write_read_binary.txt"
typedef gamer rofl;

int main(){

    rofl Platzhalter;
    //Platzhalter.set(1, 20, 30, "roflGUY");

    rofl temp;


    //ofstream HausEine;

    //HausEine.open(Pfad, ios::out | ios::binary | ios_base::trunc );

    //if(!HausEine){

    //  cerr << "Error opening file::line: " << __LINE__ << endl;

    //}

    //HausEine.write((const char*)&Platzhalter, sizeof(rofl));

    //HausEine.close();


    fstream AussaDamit;
    AussaDamit.open(Pfad, ios::in | ios::out | ios::binary);
    AussaDamit.read((char*)&tempGamer, sizeof(rofl));
    int input;
    do{
        tempGamer.get();
        cout << "set a new level: ";
        cin >> input;
        if((input >0) && (input <=170)){
            AussaDamit.read((char*)&tempGamer, sizeof(rofl));
            temp.level = input;
            AussaDamit.write((const char*)&tempGamer, sizeof(rofl));
            cout << "manipulating level succeeded!" << endl;
        } else {
            cout << "manipulating level failed! Input is not conform." << endl;
        }

    } while( input != 0);



    AussaDamit.close();

    return(0);
}


fs_class.h::

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#define MAXNAMELENGTH 100

class gamer{
public:
    int id;
    int level;
    short percent_by_level;
    char name[MAXNAMELENGTH];
public:
    void set(int id, int level, short percent_by_level, char *name);
    void get();
    void setLevel(int lvl);

}tempGamer;
//////////////////////////////////////////////////////////////////////////


//Setzen der Attribute für gamer-class

void gamer::set(int id, int level, short percent_by_level, char *name){
    this->id = id;
    this->level = level;
    this->percent_by_level = percent_by_level;
    strcpy_s(this->name, sizeof(this->name), name);
}

//Attribute über 'cout' auf Konsole ausgeben

void gamer::get(){
    cout << "id: "      << id << " "
        << "lvl: "      << level << " "
        << "percent: "  << percent_by_level << " "
        << "name: "     << name << endl;
}

//Neues Level Setzen

void gamer::setLevel(int lvl){
    this->level = lvl;
}
[/cpp]
IDE: Visual Studio Express 2008[in use]
Visual Studio 2008
SDK: DirectX SDK (August 2009)
o Windoof7 ultimate

Databyte

Alter Hase

Beiträge: 1 040

Wohnort: Na zu Hause

Beruf: Student (KIT)

  • Private Nachricht senden

2

04.03.2010, 17:19

Wie oft hast du die Klasse denn in die Datei geschriben ?
Wenn du nämlich was aus einem Stream (in diesem Fall fstream) rausliest, wird der weitergesetzt. Das bedeutet, dass du ihn zuerst wieder an den Anfang setzten musst, was mit "AussaDamit.seekg (0, ios::beg)" geht.
Das wäre aber ein bisl sinnlos, da du ja den Gamer bereits geladen hast.

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

3

04.03.2010, 17:19

Waaaaah, du kannst doch nicht direkt via Pointer eine Klasse in die Datei schreiben.... alter Schwede ^^....

Bau dir eine Stream-Klasse mit den typischen Funktionen wie int Read(void* Tar, int Size) und int Write(void* Source, int Size) und gib deinen Klassen dann jeweils die Funktionen ReadFromStream(StreamClass *Stream) und WriteToStream(StreamClass* Stream), in denen dann halt jeweils steht
Stream->Write(&id,sizeof(id));
Stream->Write(&level,sizeof(level));
...
bzw.
Stream->Read(&id,sizeof(id));
Stream->Read(&level,sizeof(level));

Um's dir noch ein wenig zu vereinfachen solltest du dem Stream noch etwas wie template <class T> int Write(T &Object) { Write(&T,sizeof(T); }
und template <class T> int Read(T &Object) { Read(T,sizeof(T); } hinzufügen, so dass du dann nur noch schreiben musst Stream->Write(id); Stream->Write(level) etc. pp.


LG
Alyx

AwesomeChick

Frischling

  • »AwesomeChick« ist der Autor dieses Themas

Beiträge: 13

Wohnort: Bayern

Beruf: Programmierer

  • Private Nachricht senden

4

04.03.2010, 17:51

Zitat von »"Databyte"«

Wie oft hast du die Klasse denn in die Datei geschriben ?
Wenn du nämlich was aus einem Stream (in diesem Fall fstream) rausliest, wird der weitergesetzt. Das bedeutet, dass du ihn zuerst wieder an den Anfang setzten musst, was mit "AussaDamit.seekg (0, ios::beg)" geht.
Das wäre aber ein bisl sinnlos, da du ja den Gamer bereits geladen hast.


jo, das mit seekg(0, ios::beg) habe ich schon versucht, hat aber nicht funktioniert gehabt.
Ich hab es genau einmal reingeschrieben. Nur die klasse, sonst nichts.
besser gesagt: ich hab es mti dem oben auskommentierten hineingeschrieben^^.
Alyx: Doch das geht sehr wohl :D

Warum es aber immer noch nicht hinhaut, kann ich mir nicht erklären.
Jedesmal wenn ich es auslese, kommt level = 20;
Entweder es wird erst gar nicht hineingeschrieben, oder es wird bei jedem neustart zurückgesetzt... habe es aber noch nicht gefunden :(
IDE: Visual Studio Express 2008[in use]
Visual Studio 2008
SDK: DirectX SDK (August 2009)
o Windoof7 ultimate

AwesomeChick

Frischling

  • »AwesomeChick« ist der Autor dieses Themas

Beiträge: 13

Wohnort: Bayern

Beruf: Programmierer

  • Private Nachricht senden

5

04.03.2010, 17:57

EDIT: habe problem gefunden.
mir bleibt nur eines übrig: lol.
Wenn man genau hinsieht wird, temp.level gesetzt, aber der spieler
tempGamer gesetzt und gelesen.(und keinem ist es aufgefallen ^^).
Aber nochmal danke für eure hilfe( die bemerkenswert schnell kam!!!).
IDE: Visual Studio Express 2008[in use]
Visual Studio 2008
SDK: DirectX SDK (August 2009)
o Windoof7 ultimate

Sylence

Community-Fossil

Beiträge: 1 663

Beruf: Softwareentwickler

  • Private Nachricht senden

6

05.03.2010, 11:37

Zitat von »"Alyx"«

Waaaaah, du kannst doch nicht direkt via Pointer eine Klasse in die Datei schreiben.... alter Schwede ^^....


Natürlich geht das. Und solange die Klasse keine Attribute enthält die Pointer sind, ist das auch der bequemste Weg.

7

05.03.2010, 13:02

Zitat von »"Sylence"«

Natürlich geht das.
Nein, das geht nur bei POD-Typen und ist sehr unflexibel. Sobald man einen Member hinzufügt, kann man alle Dateien wegwerfen. Und Portabilität kann man gleich komplett vergessen.

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

8

05.03.2010, 13:23

Sorry, aber das hat mit bequem nichts zu tun, das ist einfach extremst unsauber und würde dir bei so ziemlich jedem halbwegst vernünftigem Vorgesetzen ein sofortiges Unter-4-Augen-Gespräch garantieren. Für soetwas gibt es entweder structs und unions oder bei übersichtlichen Klassen die Referenz auf die erste Variable, aber ganz bestimmt nicht auf das Objekt.

LG
Alyx

9

05.03.2010, 14:42

Zitat von »"Alyx"«

Sorry, aber das hat mit bequem nichts zu tun, das ist einfach extremst unsauber und würde dir bei so ziemlich jedem halbwegst vernünftigem Vorgesetzen ein sofortiges Unter-4-Augen-Gespräch garantieren.
Okay.

Zitat von »"Alyx"«

Für soetwas gibt es entweder structs und unions oder bei übersichtlichen Klassen die Referenz auf die erste Variable, aber ganz bestimmt nicht auf das Objekt.
Äh, wie war das mit dem vorherigen Satz? Was ist denn jetzt genau sauberer daran, eine Referenz auf die erste Variable statt eines Zeigers auf das Objekt zu haben? Die Referenz ist ja noch viel schlimmer, da man sich auf interne Datenrepräsentierungen verlässt. Man muss die Variablen offenlegen, nur schon eine Umordnung der Membervariablen macht den gesamten Anwendercode unbrauchbar. Sowas macht man sicher nicht.

Structs und unions sind auch Sprachmittel, die eher in C ihre Verbreitung haben. Normalerweise kapselt man in C++ seine Klassen. Entsprechend fallen die hier genannten Vorschläge weg.

Eine wirklich saubere Lösung wäre zum Beispiel eine freie Funktion, welche die Eigenschaften einer Klasse über Get-Methoden abfragt und entsprechend in einem Stream speichert. Diese könnte für serialisierbare Klassen und primitive Typen überladen werden. Bei letzteren kann man direkt binär schreiben und lesen, Klassen rufen die Funktion für jeden Member auf. Als Alternative zu freien Funktionen kann man bei Klassen auch Memberfunktionen einrichten. Das hat den Vorteil, dass auch private Daten serialisiert werden können, die nicht zum Interface der Klasse gehören. Andererseits hat man keine einheitliche Syntax mehr und muss intrusiv vorgehen, was nicht immer möglich ist. Je nachdem kann auch friend angebracht sein.

Mit diesem Ansatz kann das Schreiben/Lesen rekursiv erfolgen, als Resultat davon ergibt sich eine baumartige Hierarchie. Wenn man sein Design gut durchdenkt, kann man sogar den Serialisierer und das serialisierte Objekt entkoppeln, und so ohne die serialisierten Klassen anzufassen das Format ändern (z.B. von binär zu Text). Die Bibliothek Boost.Serialize hat eine schöne Implementierung und ist auf jeden Fall einen Blick wert.

Alyx

Treue Seele

Beiträge: 236

Wohnort: Hannover

Beruf: Head Of Software Development

  • Private Nachricht senden

10

06.03.2010, 01:04

Bzgl. der Kapselung: Ok das hätte ich dazu schreiben müssen, aber es war in Hinsicht auf mein vorheriges Post mit SaveToStream bzw. LoadFromStream.

Bzgl. dem Umordnen der Membervariablen:
Wie auch im vorherigen Post schon geschrieben schließe ich mich dem an, allein schon deswegen um bei verschiedenen Versionen die evtl. verschwindenden bzw. neu hinzu kommenden Elemente sauber verwalten zu können. Es ging mir dabei eher um eine zumindest sauberere Alternative als ein völlig blinder Write(this,sizeof(*this)).

Bzgl. Unions/Structs:
Ich muss dir zustimmen, dass es extrem wenige Anwendungsfälle gibt. Zwei Top-Beispiele die mir auf anhieb einfallen sind Variants und Matrizen, wo im letzteren Fall eine Union/Struct-Kombi für ein double [4][4] vs. Vector4D[4] das Leben schon einfacher machen.

LG
Alyx

Werbeanzeige