# zahl in datei speichern und wieder auslesen



## Supa (15. September 2004)

hallo... ich will einen kleines rechen programm schreiben, das das ergebniss in eine datei speichert, damit ich dieses bei einem programm neustart wieder zum weiterrechner benutzen kann.

folgender lösungsansatz ist bereits vorhanden:


```
void __fastcall TForm1::Button1Click(TObject *Sender)
{
   FILE *stream;
   stream = fopen("test.abc", "w+");
   fprintf(stream, "%d", StrToInt(Edit1->Text));
   fclose(stream);
}
```
bis hier hin  das auch wunderbar. ich geb eine zahl im TEdit1 ein und die wird als text in die datei "test.abc" geschrieben.

dann wollte ich die zahl aus der datei wie folgt wieder auslesen:

```
void __fastcall TForm1::Button2Click(TObject *Sender)
{
   FILE *stream;
   char test[9];

   stream = fopen("test.abc", "r");
   fread(test, 9, 1, stream);
   Edit2->Text=test;
   fclose(stream);
}
```

wenn ich jetzt auf den zweiten butten drücke, schreibt er auch die zahl aus der datei in das zweite TEdit2.

nun zum problem: wenn in der datei eine zahl mit 4 oder 8 zeichen, z.b. "1234" oder "12345678" steht, wird mir in Edit2 so ein komisches "zeichen-wirr warr"  ("xÍ") mit angehangen. und dann lässt sich der string logischerweise nicht mehr in eine integer zahl umwandeln und ich kann nicht mehr damit rechnen.

also, wäre nett, wenn mir jemand sagen könnte, wie ich dieses "zeichen wirr warr" wieder weg bekomme, bzw. noch besser, wie ich machen kann, das es garnicht erst endsteht.

herrzlichen dank schonmal

mfg Dennis


----------



## lindin (15. September 2004)

Hast Du schonmal versucht die Datei mit "rb" auszulesen? Und dann vielleicht auch mit "wb" reinzuschreiben?


----------



## Supa (15. September 2004)

ja, das hab ich bereits mit der zeile:

```
_fmode= O_BINARY;
```
versucht... es ändert sich jedoch nichts.

Edit:
 wenn ich mir die erstellte datei in einem texteditor anschaue, sind diese "komischen zeichen" auch nicht da. 
ich denke mal, das der fehler sich beim auslesen der datei dazwischen mogelt.


----------



## lindin (15. September 2004)

Also wieso liest Du denn 9 ZEichen aus?


----------



## Supa (15. September 2004)

es ist völlig egal, wieviele zeichen ich auslese! ich könnte auch die länge festellen, und die dann statt der 9 hinschreiben, das ändert aber nichts an der tatsache, das bei 4 und 8 zeichen, immer so ein wirr warr dahinter gesetzt wird.

hast du das mal ausprobiert, oder stützen sich deine vorschläge und ideen nur auf spekulationen? (nicht das das schlimm wäre, schließlich bist du im moment der einzige, der versucht zu helfen)

9 zeichen, weil sich mehr als neun zeichen nicht sicher in Integer umwandeln lassen.


----------



## Beichtpfarrer (15. September 2004)

```
...
   FILE *stream;
   char test[9];

   stream = fopen("test.abc", "r");
   fread(test, 9, 1, stream);
   Edit2->Text=test;
   fclose(stream);
}
```

Edit2->Text = text

weisst du, was das macht?
Von welchem Typ ist denn Edit2->Text?
char* Edit2->Text; ?
Wenn ja: das stellt den Zeiger auf eine lokale, also nur temporär gültige Addresse ein.
Effekt ist, dass wahrscheinlich beim nächsten Funktionsaufruf einer beliebigen Funktion, der String überschrieben wird.
(Nur nebenbei bemerkt, würde das auch zu einem Speicherleck führen)
Aber wenns std::string oder so ist, will ich ja mal nix sagen...

Ausserdem ist es sehr unschön, fread(..9,1,..) zu verwenden.
Das liest einfach nur bis zu 9 Bytes ein. Das darauffolgende Byte wird dann nicht '\0' gesetzt, ausserdem, deswegen wird ja auch so ein Zeichengewirr angehängt -> weil der String nicht an der richtigen Stelle terminiert wird, wenn du Pech hast, wird er nicht mehr terminiert, bevor er in prozessfremden Speicher gelangt und das führt dann zum Programmabsturz wegen nicht genemigtem Lese-Zugriff. Willst du das umgehen könntest du zB einfach das ganze Array bei Initialisierung '\0' setzen und dafür um 1 länger machen.
...... naja, da gibts weitere Gründe, die dagegen sprechen, es so zu machen (fread(...)), auch wenn sie mir grade nicht einfallen.. 

mach doch lieber sowas ähnliches wie:

```
int val;
fscanf(stream,"%d",&val); //wenn du schon fprintf benutzt.
IntToStr(Edit2->Text,val); //such dir sowas, oder mach es selber...
```


----------



## Supa (15. September 2004)

ja, das mit der terminierung durch "\0" hab ich auch gerade gelesen! ich werd das gleich mal ausprobieren.

das das mit fread(...,9,1...) nicht schön ist, weis ich auch! es soll auch erstmal nur ein test sein, ob das überhaupt funktionieren würde. deshalt hab ich mir da jetzt nicht die mühe gemacht und keine routine zum festellen der länge geschrieben. kommt aber sicherlich noch 

naja... und wenn jemand eine andere/bessere idee hat, wie mal eine zahl oder einen AnsiString speichern kann, um sie dann beim erneuten programm aufruf wieder benutzen zu können, dann kann er diese hier gerne posten. ich bin nicht auf fread/fprintf fixiert, das waren nur meine ersten schritte in diese richtung! 
bei den programmen die ich bis jetzt geschrieben hab, musste ich nie werte speicher um sie nach einem neustart wieder auszulesen. ich hatte da alles in datenbanken gespeichert.


----------



## Beichtpfarrer (15. September 2004)

nutz ofstream.

ofstream x("datei.txt");
x << zahl;


----------



## Supa (16. September 2004)

edit: der post, kann gelöscht werden! der doppelpost war ein versehen!


----------



## Supa (16. September 2004)

also, das mit dem iostream in eine datei schreiben funktioniert ja ganz gut. danke für den tipp. das ist auch ne nummer einfacher als mit fprintf  
allerdings klappt das mit den auslesen immernoch nicht so richtig!

auslesen könnte man die datei ja dann mit:

```
ifstream x("test.txt");
x >> Edit1->Text;
```
aber das funktioniert irgendwie nicht richtig. der compiler spuckt folgende Fehlermeldung aus:

[C++ Fehler] Unit1.cpp(213): E2094 'operator>>' ist im Typ 'ifstream' für Argumente des Typs 'AnsiString' nicht implementiert

woran liegt das und wie kann ich mir da abhilfe schaffen?


----------



## Supa (16. September 2004)

juhu, hab endlich die lösung.
zum schreiben der datei:

```
#include <fstream.h>

void __fastcall TForm1::Button1Click(TObject *Sender) //Button zum schreiben
{
  ofstream file("bla.bla");
  file << "1234\n";
  file << "1111\n";
}
```
und zum lesen:

```
#include <fstream.h>

void __fastcall TForm1::Button2Click(TObject *Sender) //Button zum einlesen
{
ifstream file("bla.bla");
char buf[10];

int i;
file.getline(buf,10);
Edit7->Text=IntToStr(i=atoi(buf));

int x;
file.getline(buf,10);
Edit8->Text=IntToStr(x=atoi(buf));
}
```

danke für eure Hilfe!


----------



## Beichtpfarrer (16. September 2004)

Das geht sicher viel schöner. Deine Lösung mit atoi und IntToStr usw ist nicht besonders elegant, ausserdem entzieht sich mir ihr Sinn. (Du liest in ein char-buffer ein, konvertierst das in int, den du in (in im Folgenden unbenutzen) Variablen speicherst und wandelst das Ergebnis wieder in einen String um).

Sag doch einfach mal, welchen Datentyp hat

Edit8->Text

class AnsiString[ ...}; ?
wenn ja: les doch einfach in den Buffer ein und mach dann Edit8->Text=buf; so ne Klasse hat normalerweise Zuweisungoperatoren für Zeiger auf Strings.

oder ist das nur ein Ausdruck des Compilers?


----------



## Supa (16. September 2004)

> Das geht sicher viel schöner. Deine Lösung mit atoi und IntToStr usw ist nicht besonders elegant, ausserdem entzieht sich mir ihr Sinn.


 ich bin mir auch ziemlich sicher, das das viel schöner geht. aber die frage ist: wie? wie ich schon geschrieben hab, bin ich da für vorschäge immer offen.

und ja, Edit1->Text is ein AnsiString. das problem meiner seits ist es, der AnsiString in char umzuwnadel und andersherum.




> (Du liest in ein char-buffer ein, konvertierst das in int, den du in (in im Folgenden unbenutzen) Variablen speicherst und wandelst das Ergebnis wieder in einen String um).


 ich wandele den buffer in Int um und weise ihm eine variable zu, weil ich mit den werten ja später noch rechnen will (ist im beispiel noch nicht eingebaut). das das im obigen beispiel überflüssig ist, ist mir hinterher auch aufgefallen 



> so ne Klasse hat normalerweise Zuweisungoperatoren für Zeiger auf Strings.


 das versteh ich nciht... ich bin wohl oder übel auch noch ein blutiger anfänger! mit klassen, zeigern, zuweisungsoperatoren und solchen fachbegriffen hab ich's noch nicht so 


also, ich fände es gut, wenn jemand mal ein konkretes beispiel schreiben würde.
z.b. einen quelltext in dem ein AnsiString und eine Integer Zahl in eine datei gespeichert werden (wie auch immer)
und danach wieder von dort ausgelesen werden und ich zum schluss wieder einen AnsiString und eine Integer Zahl habe

ich wäre dem jenigen echt sehr verbunden!

edit: rechtschreibfehler ;-)


----------



## Beichtpfarrer (16. September 2004)

Ich kenn den Typ AnsiString nicht.
Nimm doch was normales, damit sollte das kein Problem sein.
std:string aus <string.h>
oder einfachen char-buffer.



> ich wandele den buffer in Int um und weise ihm eine variable zu, weil ich mit den werten ja später noch rechnen will (ist im beispiel noch nicht eingebaut). das das im obigen beispiel überflüssig ist, ist mir hinterher auch aufgefallen


Oki  , sah nur ohne das zu wissen ziemlich sinnfrei aus.


Und dann habe ich noch eine ziemlich grundlegende Frage zu deinem Problem:
warum ist Edit1->Text vom Typ AnsiString, also einer Klasse, die extra dafür geschaffen wurde, nur Strings zu bearbeiten, wenn du doch weisst, dass sie einen Integer enthält?


----------



## Supa (16. September 2004)

aso...du kennst das garnicht... hmm...
also mir fällt auch gerade auf, das das forum ja nochmal unterteilt ist, ich glaube ich hätte das problem besser in  "Borland CBuilder und VCL" posten sollen, denn ich benutze den Borland c++ Builder...aber is ja jetzt auch egal...

das ist warscheinlich auch der grund, warum du TEdit nicht kennst! Der c++ Builder mit dem ich programmiere hat eine visuelle programmier umgebung(oder wie auch immer man das nennen mag).



> warum ist Edit1->Text vom Typ AnsiString, also einer Klasse, die extra dafür geschaffen wurde, nur Strings zu bearbeiten, wenn du doch weisst, dass sie einen Integer enthält?



TEdit ist ein klasse(korrigiere mich, wenn ich mich irre), die ein eingabefeld darstellt, in dem ich alle möglichen zeichen eingeben kann die ich mit Edit->Text als AnsiString auslesen kann. wenn ich da jetzt eine zahl eingebe und damit rechnen will muss ich sie vorher mit der funktion "int x=StrToInt(<meinAnsiString>);" in eine Integer Variable umwandeln.


----------



## Supa (17. September 2004)

*Die Lösung des Problems:*

also, ich hab je eine möglichkeit gefunden, AnsiStrings zeilenweise ein eine datei zu schreiben.


```
String array[35]; // in diesem String-Array leg ich meine Strings ab...
array[0]="hallo...";
array[1]="Wie geht's?";
.
.
.
ofstream file("test.FIL"); 
 for(int i=0;i<35;i++)
 {
 char *ch = new char[array[i].Length()+1];
 strcpy(ch, array[i].c_str()); //der AnsiString wird in char umgewandelt...

  file << ch << "\n"; // der Ansistring wird als char in eine Zeile der Datei "test.FIL" geschrieben

 delete [] ch;
 }
```
 und dann wieder aus zu lesen:

```
String array2[35];

ifstream file("test.FIL");
char buf[100];
int iLength=0;

for (int i=0;i<35;i++)
{
 file.seekg(iLength);
 file.getline(buf,100);
 array2[i]=buf;
 iLength=iLength+array2[i].Length()+2;
}
```
wie man die eingelesen daten jetzt wieder aus dem array raus bekommt, brauch ich wohl nicht zu beschreiben, oder?

naja... soviel zu diesem thema. wollt das nur nochmal für die nachwelt festhalten. vieleicht hat ja jemand mal das selbe problem wie ich 

danke für die denkanstöße und die tipps

mfg Dennis


----------

