TDateTime in Datei speichern
-
Hallo,
Ich würde fstream nicht vergessen sondern statt dessen verwenden. Das Lesen/Schreiben mit fstream im Textformat ist nämlich recht einfach. Am Besten ist es noch du spendierst deiner struct read und write Funktion um das Ganze zu vereinfachen.
Bsp.// Deklaration struct Ttermin { TDateTime zeit; AnsiString ort; AnsiString titel; short repeating; int remindtime; void write(std::ostream& out); }; // Definition void Ttermin::write(std::ostream& out) { out << zeit << " " << ort.c_str() << " " << titel.c_str() << " "; out << repeating << " " << remindtime << "\n"; } // Verwenden Ttitel titel; // irgendwie füllen // und jetzt schreiben ofstream raus("Test.txt"); titel.write(raus);Das read wird dann ähnlich gemacht.
-
out << zeit << " " << ort.c_str() << " " << titel.c_str() << " "; out << repeating << " " << remindtime << "\n";Das sieht mir ein wenig gefährlich aus, was wenn in den strings auch leerzeichen enthalten sind ? vielleicht sollte ein anderes trennzeichen anstelle von " " gewählt werden, es sei denn das ich da jetzt ne kleinigkeit übersehen habe, aber ich lass mich gern eines besseren belehren
-
Wenn Leerzeichen im String enthalten sein können, geht das natürlich nicht so. Da gibt es dann verschiedenen Lösungswege.
1. andere Trennzeichen verwenden
2. Strings immer in "" einschließen.
3. jeden Wert in einer eigenen Zeile speichern
Bei diesen Varianten muß man dann beim Einlesen immer die ganze Zeile (mit getline()) einlesen und dann bei 1. und 2. wieder außeinandernehmen.
-
ja der in string gecastete TDateTime wert enthält ein leerzeichen, aber ich kann ja als trennzeichen irgendein exotisches ascii zeichen nehmen, das ist kein problem.
Ich kann jetzt schon garnicht glauben, dass ich nen ganzes wochenende damit verbracht habe, zwei simple routinen für lesen und schreiben von dateien zu basteln. In C hätte mich das eine minute gekostet... da sieht man mal wie wenig ahnung ich eigentlich von Cbuilder habe

gleich noch ne frage.
Wäre es sinnvoll die Daten weiterhin als AnsiString im struct zu speichern oder lieber nen char*, weils halt keine klasse ist, und somit leichter zu handhaben wäre. Dann könnte ich auch mein geliebtes malloc verwenden

-
malloc im cbuilder iss nicht unbedingt das beste, wenn du arrays allokierst (wie buchstabiert man das nochmal Q_Q) dann mach es besser so:
char* Array = new char[xyz]; // do sth. delete[] Array;ich finde das sieht viel sauberer aus!
für den fall das du deine stringlänge limitieren kannst empfiehlt es sich, ein festes array in die struct einzuplanen, weil sonst müsstest du schwer darauf achten das deine pointer nicht zufällig ins nichts zeigen oder dein speicher nach 20 aktionen schön zerlöchert ist _ (also delete oder free vergessen bevor die zeiger gelöscht wurden) .... wenn du mit char* arbeitest dann füge noch die stringlänge in den struct mit ein.
[EDIT] gelöscht wegen zu viel arbeit!!!ach nee lass es lieber, das artet zu sehr in denksport aus, machs wie braunstein und mit speziellem trennzeichen, ich find die idee schon vorzüglich.
-
@It0101
Was liebst du so an malloc?
Halte dich lieber an die Ratschläge und verwende in C++ grundsätzlich new/delete (wenn überhaupt). Wenn du malloc und new mischst bekommst du nur Probleme.
-
naja gut, dann werd ich wohl umlernen müssen. Wenn ich dann schon Cbuilder programmiere, dann werd ichs gleich richtig machen. Also mit AnsiString und new und delete...
Dann muss ich wohl auch von meiner einstellung weg, dass globale variablen pfusch sind, und nur lokale variablen sauberes programmieren sind

EDIT:
ich werd das speichern und laden wohl mit StringList noch mal versuchen.
den GesamtString beim Laden auseinander zu popeln krieg ich hin.TStringList *list = new TStringList(); list->Add(MeinString); list->SaveToFile("c:\\test.txt"); delete list;Aber wie mach ich den ersatz von malloc? Also wie erzeuge ich ein array meines structs nur mit new ?
wenn mir das noch einer beibringt habt ihr mir komplett bekehrt so dass nicht mal akari noch meckert

-
mir fällt grad ein schwerwiegendes problem auf, wie kann man einem TDateTime
einen zeitwert zuweisen ?
ich denke du solltest hier auch noch ein wenig umdenken, denn das mit dem
out << (TDateTime) time
klappt nicht so ganz, mal ebgesehen davon das das lesen prinzipiell unmöglich sein wird ?!
für den fall das du dein datum auch noch in separaten int werte teilst, kannst du doch einen struct mit char* machen, iss halt nur ein wenig mehr arbeit beim löschen btw. einlesen (erst l-wert lesen, speicher allokieren dann auslesen und kopieren)
und in dem struct würd ich dann sowieso einen destruktor einbauen der automatisch den speicher wiedeer freigibt.struct Ttermin { TMyTimeStruct zeit; (also n struct fürs datum basteln) int ortlen; char* ort; int titellen; char* titel; short repeating; int remindtime; ~Ttermin(); bool ReadFromStream(TMemoryStream t); void WriteToStream(TMemoryStream t); }; Ttermin::~Ttermin() { delete[] ort; delete[] titel; } bool Ttermin::ReadFromStream(TMemoryStream t) { if ((t.Position+sizeof(Ttermin)) > t.Size) return false; // das if beachtet NICHT die länge der strings, es kann also ein pufferüberlauf stattfinden wenn du die längen nicht richtig angibst!!!! t.read(&zeit, sizeof(TMyTimeStruct )); t.read(&ortlen, sizeof(ortlen)); ort = new char[ortlen]; t.read(ort, ortlen); t.read(&titellen, sizeof(titellen)); titel = new char[titiellen]; t.read(titiel, titellen); t.read(repeating, sizeof(repeating)); t.read(remindtime, sizeof(remindtime)); return true; } void Ttermin::WriteToStream(TMemoryStream t) { t.write(&zeit, sizeof(TMyTimeStruct )); t.write(&ortlen, sizeof(ortlen)); t.write(ort, ortlen); t.write(&titellen, sizeof(titellen)); t.write(titiel, titellen); t.write(repeating, sizeof(repeating)); t.write(remindtime, sizeof(remindtime)); } //in der application vector<Ttermin> Termine; Ttermin Termin; while(Termin.ReadFromStream(MyFileStream)) { Termine.insert(Termine.end(), Termin); } while(Termine.size()) { Termine.begin()->WriteToStream(MyFileStream); Termine.erase(Termine.begin()); }weia so viel code ausm kopf und dann ohne compiler .... hoffentlich hab ich nich zu viel mist gbaut *duck
-
Hallo
irgendwie kann ich nicht verstehen, warum ihr soviel Terz um das Speichern von TDateTime macht.
Speichern : Mit TDateTime::DateString oder ::FormatString in AnsiString umwandeln, AnsiString in Stream schieben
Laden : AnsiString wie üblich bis Trennzeichen lesen, mit StrToDate in TDateTime umwandeln.Für das alles braucht man wenn man es richtig macht (also rein mit VCL oder Standard-Mitteln) kein new oder gar malloc.
bis bald
akari
-
StrToDate
sry kannte ich noch nicht ...
mir fällt grad auf, das man statt den arrays auch einfach den text aus dem stream in ein AnsiString kopieren kann, hast ja recht, geht auch ohne ^^
in meinem jetzigen projekt soll ich nur wo immer auch möglich AnsiStrings vermeiden um aus dem VCL rauszukommen, deswegen denk ich immer ein wenig abstrakt in der beziehung.
-
irgendwie kann ich nicht verstehen, warum ihr soviel Terz um das Speichern von TDateTime macht.
je mehr posts ich von dir lese, um so mehr drängt sich mir der gedanke auf das du überheblich bist aufgrund deines überaus fundamentierten wissens .... überdenk bitte deine schreibweise, ich fand das oben zitierte nämlich sehr unhöflich!
Schliesslich hat nicht jeder die borland-hilfe einmal komplett rauf und runtergelesen ...entschuldigt bitte den spam, ich wollte nur helfen und werde dafür runtergemacht, das passt irgendwie nicht in ein forum ....
mfg
Ceos
-
Hallo
Wenn du aus der VCL rauskommen willst, solltest du aber auch kein TDateTime verwenden...
Dann wäre es nur konsequent, die Typen std::fstream, std::string und time_t aus dem C/C++ Standard zu verwenden. Die letzen beiden machen aber nur Sinn, wenn keine direkte Verarbeitung mit VCL-Controls erfolgen soll, also zum Beispiel in einer GUI-unabhängigen Library. Wenn dann das in DLL ausgelagert werden soll, lohnt es sich auch wieder über ein C-Interface nachzudenken.bis bald
akari
-
Hallo
Ceos schrieb:
je mehr posts ich von dir lese, um so mehr drängt sich mir der gedanke auf das du überheblich bist aufgrund deines überaus fundamentierten wissens .... überdenk bitte deine schreibweise, ich fand das oben zitierte nämlich sehr unhöflich!
Schliesslich hat nicht jeder die borland-hilfe einmal komplett rauf und runtergelesen ...entschuldigt bitte den spam, ich wollte nur helfen und werde dafür runtergemacht, das passt irgendwie nicht in ein forum ....
Mein Post (und auch die andern) war nicht überheblich gemeint. Wenn es so rüberkam bitte ich um Entschuldigung.
Sei beruhigt auch ich schreibe hier im Forum noch manchmal Unsinn, und werd dafür (aus meiner Sicht) teilweise recht rüde zurechtgewiesen.bis bald
akari
-
leider ist es nicht so einfach, ich muss eine komponente(package) neu entwickeln, mit einer socketkommunikation statt einer bisher verwendeten DCOM kommunikation, das problem ich bin an die VCL behaftete schnittstelle gebunden und muss deshalb sehr häufig konvertieren ... zum glück wir der spass dann gemergt (nicht von mir) und dann VCL frei umgeschrieben.
zum topic, ich hab wie gesagt bei meiner lösung kein TDateTime und auch kein AnsiString benutzt, eben etwas abstrakt und normale strings ..... naja hab mich noch nicht allzusehr damit beschäftigt ....
-
Warum nimmst du da char* und nicht std::string (oder meinetwegen AnsiString)? Desweiteren willst du ja deine Klasse in einen vector packen. Dazu benötigst du bei deiner Form noch Konstruktor, CoypCtor und Zuweisungsoperator. TDateTime ist ja wie schon gesagt auch nur ein double. Somit könnte man diese intern auch so verwenden.
-
ich danke euch erstmal für die hilfe.
Ich werds mal so versuchen wie Ceos es hier probert hat, und ich werds mal komplett über TStringList testen. Irgendwie wirds schon gehen, wenn nicht, werd ich eben gärtner...