Daten in Binärdatei werden überschrieben
-
Hallo liebe Community,
Zu aller Erst möchte ich erwähnen dass ich, wie mein Pseudo schon sagt ein totaler Anfänger bin. Bin Einsteiger in C++ und habe ein Problem bei meinem ersten Programm dass ich mir komplett alleine (also ohne irgendwelche Beispiele die man nur abtippen muss) erarbeiten möchte.
Zunächst mal dass Programm dann die Erläuterung:
#include <iostream> #include <fstream> using namespace std; struct Datensatz { char Name[10]; char Vorname[10]; char Telefonnummer[20]; }Daten[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; int main() { int Menue; int Position; do { cout << "1. Telefonnummer hinzufügen/bearbeiten" << endl; cout << "2. Telefonnummer ansehen" << endl; cout << "0 zum Beenden" << endl; cin >> Menue; switch (Menue) { case 1: { fstream Datei; Datei.open("test.dat", ios::out | ios::binary); { cout << "Position: " << endl; cin >> Position; cout << "Name: " << endl; cin >> Daten[Position].Name; cout << "Vorname: " << endl; cin >> Daten[Position].Vorname; cout << "Telefonnummer: " << endl; cin >> Daten[Position].Telefonnummer; } Datei << Daten[Position].Name << endl; Datei << Daten[Position].Vorname << endl; Datei << Daten[Position].Telefonnummer << endl; } break; case 2: { fstream Datei; Datei.open ("test.dat", ios::in | ios::binary); { cout << "Welche Position moechten Sie auslesen: " << endl; cin >> Position; } Datei >> Daten[Position].Name; Datei >> Daten[Position].Vorname; Datei >> Daten[Position].Telefonnummer; cout << Daten[Position].Name << endl; cout << Daten[Position].Vorname << endl; cout << Daten[Position].Telefonnummer << endl; } break; } } while (Menue!=0); system("PAUSE"); return EXIT_SUCCESS; }Was soll dass Programm eigentlich tun?
Ansich leicht zu erkennen, ich möchte eine Art Adressbuch schreiben auf dem ich nach und nach aufbauen kann. Dass ganze sozusagen zu Übungszwecken.
Mein Problem:
Dass Programm selbst funktioniert tadellos bis auf ein kleines Detail was die dauerhafte Speicherung meiner eingegeben Daten angeht.
Ums verständlich auszudrücken:
Ich starte dass Programm und möchte natürlich erstmal Daten speichern, dazu gebe ich bei der Frage zur Position "1" ein. Dann beschrifte ich diese nach und nach. Danach springt dass Programm wieder zum Programmstart. Jetzt wiederhole ich dass ganze, nur eben mit Position "2".
Wenn ich jetzt aber die Daten auslesen möchte und gebe als Position "1" an, zeigt er mir die Daten von Pos. "2" an. Auch wenn ich die Datei öffne steht dass gleiche drin. heißt also bei jeder neuen Eingabe ingnoriert mein Programm die Position und überschreibt einfach die alte, die dann auf jeder Position ansprechbar ist, oder ähnliches.
Meine Vermutung ist, dass etwas mit meinem Array nicht stimmt. Leider finde ich den Fehler nicht, wenn aber einer von euch da mal kurz drüber gucken würde und mir helfen könnte wäre dass toll.
PS: Wenn möglich keine kompletten Codes sondern einfach einzelne Zeilen oder Denkhilfen.
MFG Marcel
-
Schreiben in die Datei, ohne die Daten zu überschreiben (mit ios::app):
fstream Datei("test.dat", ios::out | ios::app | ios::binary);Am besten gleich den Konstruktor der Stream-Klassen verwenden und das erstellte Objekt initialisieren.
Grüße,
Rewind.
-
Du öffnest die Datei mit Modus ios::out (dabei wird der Schreibzeiger an den Dateianfang gesetzt) und schreibst dann einen Datensatz dort rein - da ist klar, daß dann alles weg ist. Du mußt dich schon bis zur richtigen Position durchhangeln, wo du schreiben willst.
Ich würde dir empfehlen, die Datei einmal bei Programmstart einzulesen und am Ende komplett zurückzuschreiben - dazwischen arbeitest du dann mit den Daten im Array.
PS: Und ich empfehle std::string und std::vector<>

-
Ich habe jetzt mal die Verbesserung von Rewind versucht, leider ohne Erfolg, dass Programm macht immer noch dass gleiche. Was mich ja wundert ist dass, trotz des Arrays dass ich im Struct mit eingebunden hab, die Daten bei allen Positionen ausgegeben werden. Scheint also als würde er mein Array total ignorieren.
zu Cstoll:
Wie man eine Datei gleichzeitig zum Schreiben und zum Lesen öffnen kann hab ich ehrlich gesagt noch nicht herausgefunden, dachte man kann nur entweder oder. Ich werd mich da mal ransetzen, vllt lösts ja auf mysteriöse Art mein Problem.
String würde ich sehr gerne verwenden, da ich dann zumindest dass Array-Problem ausschließen könnte und ich die Variablen einzeln deklarieren könnte, Nur mag Bloodshed diese Funktion nicht, auch wenn die Header datei vorhanden wäre. Wenn ich aber die Variablen "Name, Adresse, Telefonnummer" einzeln via String deklariere, schimpft mich der Compiler von wegen "Invalid Conversion".
Kurz: String fällt weg, ich muss die Zeichenketten also von Char ableiten.
Vector ist mir bisher ehrlich gesagt noch nicht bekannt aber ich werd mir dass auch noch genauer ansehen.
Erstmal danke für die Antworten
-
Generell, was mir auf den ersten Blick auffaellt:
- Du beruecksichtigst schon, dass ein Array in C/C++ 0 basierend ist. Also wenn du 1 angibst, du Den "logisch gesehen" 2. Datensatz bekommst ?
- Du speicherst das Komplette Buch. Wenn das mal Groesser ist ....
Gewoehn dir gleich an, das Datei-Inhalte Umfänge haben koennen die nicht mehr in den Speicher passen koennen.
Deine Strukur dazu ist gar ned mal so ungeeignet, nur nimm das Array raus, und "verwalte" die "Menge" über Datei. Sollte ne gute Übung sein wie man mit Datei-Posizeigern arbeitet.struct Datensatz { char Name[10]; char Vorname[10]; char Telefonnummer[20]; } Daten[]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};Das funktioniert ?
Was soll in einem Datensatz drinnestehen, den man mit "1" initialisiert ?
Bin mir ned sicher, aber glaub mein compiler wuerde das ned schlucken ...
Oder hab ich irgendwo nen Denkfehler grad ...Wie gesagt, nimm das Array raus ...
struct Datensatz { char Name[10]; char Vorname[10]; char Telefonnummer[20]; } ;Lass das Programm immer nur einen so einen Datensatz im Speicher haben.
Les auch immer nur einen Datensatz ein ... wenn der user den 5. berabeiten will, beweg den File-Positionszeiger an die Stelle in der Datei wo der 5. steht.
Voiala, dann kannst plötzlich Gigabyte-weisse (32 bit Grenzen beachten !) Adressen verwalten (rudimentär).
Such mal nach den tellg und tellp funktionen.Ciao ...
-
Absoluter_Beginner schrieb:
Ich habe jetzt mal die Verbesserung von Rewind versucht, leider ohne Erfolg, dass Programm macht immer noch dass gleiche. Was mich ja wundert ist dass, trotz des Arrays dass ich im Struct mit eingebunden hab, die Daten bei allen Positionen ausgegeben werden. Scheint also als würde er mein Array total ignorieren.
Es fällt mir wirklich schwer, dir zu glauben. Überschreibt er immer noch die Datei bei jedem einzelnen Zugriff? Ich tippe eher, dass die Ausgabe nicht funktioniert. Ich gebe zu, ich war etwas zu faul, mir deinen Code genauer anzuschauen, aber wie ich sehe, ist es auch kein Wunder, dass es nicht funktioniert, denn du versuchst den ganzen Inhalt der Datei in deine Struct-Attribut hineinzupressen. Dass da etwas sinnvolles ausgegeben wird, ist wahrscheinlich eher Zufall.
Zu deinem Struct: du musst nicht im Vorfeld schon 20 structs erzeugen, wenn sowieso nicht auf alle zugegriffen wird. Was hindert dich daran, die Position des Telefonsbucheintrags (oder so) als ein Element des struct zu implementieren? Dann verstehe ich aber immer noch nicht, warum du std::string nicht verwenden kannst?#include <string> ... struct Datensatz { unsigned int Position; string Name; string Vorname; string Telefonnummer; } Daten;Wenn du die Position im struct hast, müsstest du bei der Eingabe nur überprüfen, ob die eingegebene Zahl zw. 1 und 20 liegt. Somit würdest du dir die Arrays sparen, was nur Vorteile mit sich bringt. Die Eingabe könnte dann z.B. so aussehen:
{ cout << "Position: " << endl; cin >> Daten.Position; cout << "Name: " << endl; cin >> Daten.Name; cout << "Vorname: " << endl; cin >> Daten.Vorname; cout << "Telefonnummer: " << endl; cin >> Daten.Telefonnummer; }Weiteres Problem: du verlässt dich darauf, dass der Anwender bei der Position eine Zahl eingibt (und dann auch nicht irgendeine)... Hast du dir schon Gedanken gemacht, was passiert, wenn er z.B. 'T' oder ein anderes Zeichen eingibt? Dazu würde ich dir zu sstringstream raten:
#include <sstream> ... { stringstream intStream; unsigned int evalZahl = 0; do { cout << "Position: " << endl; cin >> intStream; if (intStream.good()) intStream >> evalZahl; } while (evalZahl > 20 || evalZahl < 1); Daten.Position = evalZahl; }Den Code habe ich zwar nicht getestet, aber das müsste in etwa stimmen.
Weiteres Problem: wenn du den Inhalt der Datei so ausliest, dann wird afair der ganze Inhalt kopiert. Auch hier gibt es verschiedene C++-Ansätze. Kannst z.B. auch getline() nehmen. Oder - wie bereits gesagt - du könntest Vektoren nehmen. Wenn du allerdings eine bestimmte Zeile mit bestimmtem Inhalt haben möchtest, wirst du jede Zeile durchgehen müssen, und schauen ob das die richtige ist.
Absoluter_Beginner schrieb:
Wie man eine Datei gleichzeitig zum Schreiben und zum Lesen öffnen kann hab ich ehrlich gesagt noch nicht herausgefunden, dachte man kann nur entweder oder.
Das hast du bereits gemacht, nämlich mit
fstream. Nur mit den Flags ios::out bzw. ios::in hast du den Zugriff entsprechend eingeschränkt. Wenn du das weglässt, kannst du lesen und schreiben. (Alternativ zu den Flags gibt es auchofstreamundifstream.)P.S. mit "dass" leitet man einen Nebensatz ein, "das" = Artikel

-
Ich glaube ich sollte mein Struct etwas besser erläutern bzw was ich mir dabei gedacht hab, auch wenn mein Gedanke wohl eher falsch war:
die Zahlen in den eckigen Klammern hinter den einzelnen Variablen, also Name, Vorname und Telefonnummer sollen keine Positionen darstellen sondern lediglich ermöglichen, das Char mir mehr Speicher für Zeichen zur Verfügung stellt, also ich mehr als nur 1 Zeichen darin speichern kann. Das Array das ich am Schluss dazu geschrieben hab sollte dann die Positionen der einzelnen Einträge darstellen damit diese später auch wieder anhand der Positionsnummer abrufbar sind. Die Struktur habe ich lediglich geschrieben, weil mein Compiler eben String nicht mag, trotz #include <string> (und ja, die Headerdatei liegt im richtigen Ordner, hab es aber auch mit Pfadangabe usw. versucht half auch nix).
zu den Arrays selbst: Natürlich beginnen Arrays mit 0 aber sind die Angaben in {} nicht dazu da die einzelnen Werte zu definieren? im Klartext also:
0=1
1=2
usw.abgesehen davon würde auch dass nichts ändern, denn dass programm gibt mir an jeder position, die Daten aus die ich zuletzt eingegeben habe, ob 1,2 oder 15 spielt keine Rolle. Auch wenn ich die Datei mitm Editor öffne steht nur immer der letzte Eintrag drin.
Naja, ich werd mich wohl doch erst noch etwas mehr einarbeiten müssen in die ganze Materie, bin halt vor kurzem von Pascal umgestiegen und das ist halt um Welten einfacher bzw. selbsterklärender gestaltet.
Auf jeden Fall Danke für die ganzen Antworten und Erklärungen, hat mir echt weitergeholfen. Programm funktioniert zwar noch nicht, aber ich hab gemerkt dass mir noch viel zu viel Wissen fehlt.
-
Absoluter_Beginner schrieb:
weil mein Compiler eben String nicht mag
Und genau das würde ich an deiner Stelle möglichst schnell ändern. Dev-C++ wird seit 2005 nicht mehr weiterentwickelt, was häufig zu Compiler- und anderen Fehlern führt. Lade dir Visual Studio herunter. Die Express Edition ist kostenlos. Das wird dir dann Einiges einfacher machen.