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

1

25.11.2014, 15:59

std::list<class> in Datei schreiben und wieder auslesen

Hallo liebe Community,

ich bin noch nicht so gut im Programmieren und versuche einen Chat zu schreiben. Es gibt verschiedene User der Klasse der user. Die Klasse beinhaltet zwei Membervariablen vom Typ std::string, 1 std::list<int> und einen std::list<int>::iterator. Alle existierenden User habe ich in die Liste std::list<user> geschoben. Kann ich die dieser "Userliste" in einer Datei binär speichern und wieder auslesen ohne die Werte zu verlieren? Wenn ja, wie geht das?


Toboxos

Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

2

25.11.2014, 16:15

Willkommen Toboxos.

Was du tun möchtest, ist die Serialisierung und anschließende Deserialisierung einer List.

Eine Google-Suche nach "c++ serialize std::list" dürfte schnell zum gewünschten Ergebnis führen. Eventuell musst du externe Bibliotheken (Boost) nutzen, Serialisierung ist mit C++ leider nicht so einfach wie mit Java.
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

3

25.11.2014, 17:18

Nimm außerdem einen "std::vector", der ist eigentlich immer besser. Sogar dann mit hoher Wahrscheinlichkeit, wenn du anders vermutest.

In C++ gibt es leider aus diversen Gründen keine eingebaute Möglichkeit um diese Funktionalität zu erreichen. Tatsächlich ist es sogar relativ kompliziert, bedingt durch die Arbeitsweise der Streams in C++ die besonders zum binären Lesen/Schreiben sehr wenig bieten können. Wenn du es von Hand machen willst, musst du...
  1. Die Anzahl User schreiben.
  2. Dann die User der Reihe durch gehen und für jedes einzelne Element so speicherst...
    1. Den String kannst du speichern, in dem du erst die Anzahl Zeichen und dann die einzellnen Zeichen speicherst.
    2. Den Iterator musst du in einen Index auflösen. Also beim Speichern schauen welche Nummer die Position hat, an dem der Iterator zeigt. Beim Lesen kannst du dann entsprechend wieder einen Iterator zu dem Objekt an dem Index herstellen.
    3. Die zweite Liste(die eigentlich wieder "std::vector" sein dürfte...) musst du wieder Speichern, in dem du erst die Anzahl "int"s im Container speicherst und dann der Reihe diese selbst.

Um binäre Daten in C++ schreiben zu können, musst du leider manuell die "read" bzw. "write"-Methoden der Streams verwenden. Die überladenen Operatoren arbeiten sehr unglücklicherweise immer im Textmodus. Wenn du die Dateien auch platfformübergreifend lesen/schreiben möchtest, musst du dich auch noch selber um den Endianness kümmern. Auch hier: Dafür gibt es leider nicht mal wirklich hilfreiche Hilfsfunktionen in der STL.

Ich habe keine Erfahrung mit anderen Libs, weil ich mir mal meinen eigenen Code dafür geschrieben habe. Je nach dem was du sonst noch so vor hast, wäre es aber wahrscheinlich wirklich eine gute Idee mal zu schauen ob es da was gibt. Boost ist leider ziemlich groß.

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Spiele Programmierer« (25.11.2014, 20:05)


DeKugelschieber

Community-Fossil

Beiträge: 2 641

Wohnort: Rheda-Wiedenbrück

Beruf: Software-Entwickler

  • Private Nachricht senden

4

25.11.2014, 19:29

Du kannst auch im ASCII Format speichern, also schlicht Text.
Vorgehen könntest du so:

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
class user{
    public:
        void save(std::ofstream &outputFile);
}

void user::save(std::ofstream &outputFile){
    outputFile.write(name.c_str(), name.length);
    
    for(auto i : intlist){
        outputFile.write(/* ... */);
    }
}

// Dann an anderer Stelle:

std::ofstream outputFile("/path/to/file.txt");

if(!outputFile.good()){
    // Fehler
}

for(auto u : userlist){
    u->save(outputFile);
}


Das Auslesen ist dann etwas komplizierter, du könntest Trennzeichen nutzen oder je Zeile eine Information speichern.
Wie du das dann machst musst du allerdings selbst herausfinden.

5

26.11.2014, 00:12

[...]Wenn du es von Hand machen willst, musst du...
  1. Die Anzahl User schreiben.
  2. Dann die User der Reihe durch gehen und für jedes einzelne Element so speicherst...
    1. Den String kannst du speichern, in dem du erst die Anzahl Zeichen und dann die einzellnen Zeichen speicherst.
    2. Den Iterator musst du in einen Index auflösen. Also beim Speichern schauen welche Nummer die Position hat, an dem der Iterator zeigt. Beim Lesen kannst du dann entsprechend wieder einen Iterator zu dem Objekt an dem Index herstellen.
    3. Die zweite Liste(die eigentlich wieder "std::vector" sein dürfte...) musst du wieder Speichern, in dem du erst die Anzahl "int"s im Container speicherst und dann der Reihe diese selbst.
Nö, muss er nicht, das kann er. Auch diese save Methode und die potentielle load Methode in dem Stil sind unnötig. Es geht viel leichter.
Zum Beispiel:

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
#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>

struct to_save
{
    explicit to_save(int _a=0, int _b=0)
        : a(_a), b(_b)
    { }
    int a;
    int b;
    friend std::ostream& operator<<(std::ostream& os, const to_save& s);
    friend std::istream& operator>>(std::istream& is, to_save& s);
};
std::ostream& operator<<(std::ostream& os, const to_save& s)
{ return os << s.a << " " << s.b << "\n"; }
std::istream& operator>>(std::istream& is, to_save& s)
{ return is >> s.a >> s.b; }

int main()
{
    std::ofstream _of("data");
    std::vector<to_save> v{to_save{1, 2},to_save{3, 3},to_save{2, 1}};
    for(auto& a : v)
        _of << a;
    v[0]=v[1]=v[2]=to_save();
    _of.close();
    
    std::ifstream _if("data");
    
    std::cout << "In Datei: " << std::endl;
    for(std::string s; std::getline(_if, s); std::cout << s << std::endl)
    { }
    _if.clear();
    _if.seekg(0);
    for(auto& a : v)
        _if >> a;
    std::cout << "Neu im Container: " << std::endl;
    std::copy(v.begin(), v.end(), std::ostream_iterator<to_save>(std::cout));
}


Boost ist leider ziemlich groß.

Boost ist groß, jo, nur ist Boost ja eine Sammlung von Bibliotheken und nicht direkt eine Bibliothek selbst. Boost.Filesystem sollte man sich durchaus schon einmal ansehen, nicht zuletzt da es ja in Zukunft so allmählich in den Standard kommt. :vain:

MfG
Check

6

26.11.2014, 10:53

@Checkmateing:
So schön deine Lösung auch sein mag (wobei mir persönlich manche Schreibweisen und der leere Körper der for-Schleife nicht gefällt, aber das ist ja Geschmackssache), aber glaubst du wirklich, dass jemand der noch nicht weiß, wie man einen String binär in eine Datei schreibt Dinge wie
- explicit
- friend
- list initialization
- überladene Operatoren
- auto / range based for
- stl Algorithmen wie copy
kennt? Ich glaube es ehrlich gesagt nicht. Es ist einfach eine komplizierte Musterlösung, ohne jegliche Erklärung, und damit vermutlich ziemlich nutzlos. (Ganz zu schweigen davon, dass du keine Strings speicherst, was um einiges kniffeliger ist, wenn du erlaubst, dass Strings Leerzeichen oder gar Zeilenumbrüche enthalten dürfen...)

@Toboxos:
Mach es so wie Spiele Programmierer sagt. Das ist intuitiv und einfach. Du wirst vermutlich read und write hiervon benutzen wollen:
http://en.cppreference.com/w/cpp/io/basic_fstream
Du kannst dir auch Checkmates Lösung ansehen, du kannst davon vermutlich eine Menge lernen, aber du solltest dich nicht abschrecken lassen. Du brauchst das nicht unbedingt, um Variablen in Dateien zu schreiben.
Lieber dumm fragen, als dumm bleiben!

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

7

26.11.2014, 13:24

Mach es so wie Spiele Programmierer sagt.
Bis auf den Quatsch mit den Unterstrichen...
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Beiträge: 1 223

Wohnort: Deutschland Bayern

Beruf: Schüler

  • Private Nachricht senden

8

26.11.2014, 16:37

Zitat von »BlueCobold«

Bis auf den Quatsch mit den Unterstrichen...

Öhm, in meinen ganzen Beitrag gibt es keinen Unterstrich... :huh:

@Checkmating
Dein Code behandelt leider nicht alle notwendigen Dinge(Liste in Liste bzw. Iterator) bzw. schreibt er alles als Text und nicht binär, wonach Toboxos gefragt hatte.
Außerdem, was ist wenn ein Username ein Leerzeichen enthält? (Wie meiner zum Beispiel)

9

26.11.2014, 17:38

Dann nimmt man eben ein anderes Zeichen. ;)
@BlueCobold: Ich nehme an du meinst mich. Die Unterstriche sind natürlich nicht hübschig.
Aber es galt ja auch weniger als Musterbeispiel sondern mehr als funktionelles Beispiel.

MfG
Check

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

10

26.11.2014, 18:37

Jo, ich meinte offensichtlich Check.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige