#include "stdafx.h"
#include <stdio.h>

int main(){
/*   P R I N Z I P:
Wenn man eine Datei bearbeiten will, muß diese Datei zuerst angelegt
und dann geöffnet werden. Dabei wird der Name der Datei, wie z.B. 
"privat.txt" benutzt. NACH dem Öffnen der Datei kann man diese z.B.
beschreiben, lesen oder den sogenannten Dateizeiger der Datei 
verschieben. DAZU greift man dann nicht mehr über den Namen der 
Datei, sondern über den den sogenannten Stream, auf die Datei zu. 
Diesen Stream kann man sich z.B. als einen Zahlenwert vorstellen, 
(eindeutige Identifikation wie z.B. die Hausnummer), der vom 
Betriebssystem vergeben wurde.
*/ 
// Die Variable muß nicht stream heißen, jeder andere Name kann 
// genauso vergeben werden.
  FILE *stream;
  double z1, z2, z3, e1, e2, e3;
  char temp;
  int erg;

// Versuche, die Datei "mesk.txt" zu öffnen
  stream = fopen("mesk.txt", "r+");

/*
Wenn stream den Wert NULL zurückliefert, wurde diese Datei noch nicht
angelegt (existiert diese Datei noch nicht). D.h. sie muss vorher 
angelegt werden ! Deshalb benutzt man einen Modus (z.B. "a+") von 
fopen (siehe Hilfe zu fopen), mit dem eine noch nicht existierende 
Datei angelegt wird. Der Modus "a+" bewirkt außerdem, daß die Datei
(ob sie schon existiert oder nicht) im "Anfügemodus" geöffnet wird, 
d.h. es können nur Daten am Dateiende angefügt werden.
*/
  if(stream == NULL){
    stream = fopen("mesk.txt", "a+" );
/*
Datei wurde angelegt. Da man in diesem Modus nur Daten anfügen kann, 
schließt man sie gleich wieder. Hauptsache sie wurde angelegt!! 
Falls bei der Aktion schliessen ein (bzw. kein) Fehler passiert, 
liefern Funktionen wie fclose, fseek, fopen usw. diese Information 
(Fehler/kein Fehler passiert) zurück. Diese Information kann in 
einer Variablen gespeichert und dann 
ausgewertet werden. Wenn erg den Wert 0 hat, ist bei der Aktion 
fclose kein Fehler passiert. Sauber programmierte Programme müssen 
Fehler abfangen. Aus Gründen der Übersichtlichkeit wird dies hier 
und im folgenden im Programm nicht gemacht.
*/
  erg = fclose(stream);
// Öffne die Datei in einem Modus, so, dass sie sich an irgendeiner
// Stelle der Datei lesen und beschreiben lässt.
  stream = fopen("mesk.txt", "r+");
  }

// An dieser Stelle des Programms ist die Datei nun in so einem Modus
// geöffnet, der es erlaubt, sie an irgendeiner Stelle der Datei 
// lesen und beschreiben zu können.
  z1=3.1415;
  z2=2.718;
  z3=1.414213;
/*
Da man im folgenden den Anfang der Datei mit einer Zahl beschreiben 
will, muß man den sogenannten Dateizeiger dorthin verschieben. 
Am Dateianfang hat der Dateizeiger den Wert 0. Der Parameter 
SEEK_SET bedeutet, daß der Dateizeiger relativ zum Dateianfang 
verschoben wird und zwar hier um den Wert 0. 
Falls bei der Aktion kein Fehler passiert, wird erg gleich 0.
*/
  erg = fseek(stream, 0, SEEK_SET);
/*
fprintf schreibt z1 in die Datei. fprintf funktioniert genauso wie 
printf, außer daß nicht auf den Bildschirm, sondern in eine Datei 
geschrieben wird.
WICHTIG:
Wenn ein Wert in eine Datei geschrieben wurde, wird der Dateizeiger
AUTOMATISCH verschoben, d.h. fseek wird dazu nicht mehr benötigt.
Falls bei der Aktion ein Fehler passiert, wird erg negativ.
*/
  erg = fprintf(stream,"%f",z1);			
/*
Wenn die Zahlen direkt hintereinander in die Datei geschrieben 
werden, kann es beim Lesevorgang dieser Daten Schwierigkeiten geben,
weil dann die Lesefunktion fscanf nicht weiß, wann die eine Zahl zu
Ende ist und die neue Zahl beginnt !! (siehe Hilfe-Menü in VC++).
Deswegen schreibt man hier nach dem Ende der Zahl irgendein Zeichen
in die Datei, z.B: '#'.
*/
  erg = fprintf(stream,"%c",'#');			
  erg = fprintf(stream,"%f",z2);			
  erg = fprintf(stream,"%c",'#');			
  erg = fprintf(stream,"%f",z3);			
  erg = fprintf(stream,"%c",'#');			

// Wenn man will, dass für eine Fliesskomma-Zahl immer gleich viel 
// Platz beim Abspeichern in einer Datei verwendet wird, kann man 
// sie z.B. in Expotentialschreibweise abspeichern:
  erg = fprintf(stream,"%e",z3);			
// Folgender Text wird noch ans Dateiende geschrieben
  erg = fseek(stream, 0, SEEK_END);		
  erg = fprintf(stream,"---theoretische Informatik ist Mathematik---");

// Jetzt will man hier aus Gründen der Übung diese Zahlen wieder aus
// der Datei rauslesen. Dazu wird die Funktion fscanf benutzt. Sie 
// funktioniert genauso wie scanf, außer daß nicht von der Tastatur 
// gelesen wird, sondern aus einer Datei. Da der Dateizeiger sich
// jetzt nicht am Dateiende befindet, verschiebt man ihn an den 
// Dateianfang.
  erg = fseek(stream, 0, SEEK_SET);
// erg = fseek(stream, -1, SEEK_CUR); verschiebt relativ zum 
// Dateizeiger um 1 nach links.

/*   W I C H T I G:
Wenn ein Wert aus einer Datei gelesen wurde, wird der Dateizeiger 
AUTOMATISCH verschoben, d.h. fseek wird dazu nicht mehr benötigt.
*/

// Falls bei der Aktion ein Fehler passiert oder das Dateiende 
// erreicht wurde, wird erg gleich EOF.
  erg = fscanf(stream,"%lf",&e1);			
  erg = fscanf(stream,"%c",&temp);			
  erg = fscanf(stream,"%lf",&e2);			
  erg = fscanf(stream,"%c",&temp);			
  erg = fscanf(stream,"%lf",&e3);			
  erg = fscanf(stream,"%c",&temp);			

  erg = printf("z1=%f\n",z1);
  erg = printf("z2=%f\n",z2);
  erg = printf("z3=%f\n",z3);
  erg = printf("e1=%f\n",e1);
  erg = printf("e2=%f\n",e2);
  erg = printf("e3=%f\n",e3);

// Datei schließen		
  erg = fclose(stream);	  
  return 0;
}

/*   W I C H T I G:
1) Textmodus: (z.B: fopen("geheim.txt", "rt+"))
Ein Zeilenende wird in C durch '\n' (ASCII-Wert 10) dargestellt.
Wird mit printf nun dieses Zeilenende in eine Datei geschrieben,
werden dort die Bytes mit den ASCII-Werten 13, 10 abgespeichert.
Steht der Dateizeiger auf dem Byte mit ASCII-Wert 13 (dem 10 folgt),
liefert fscanf(stream, "%c", &z) in z nur 10 zurück, 13 wird 
unterdrückt (geht verloren). 
Deswegen ist es für uns besser, den sogenannten Binärmodus zu 
verwenden. Binärmodus (z.B: fopen("bild1.jpg", "rb+") oder 
fopen("bild2.jpg", "ab+")):
Das Byte, das geschrieben werden soll, wird auch geschrieben. 
Die Ausnahmen wie im Textmodus´gibt es nicht. Wenn in fopen der 
Schalter t (für Textmodus) bzw. b (für Binärmodus) nicht angegeben
wird, wird standardmässig t verwendet.

2) Wenn man bei fopen (siehe Hilfe-Menü) die "Schalter" r+, w+ 
oder a+ benutzt, darf nicht sofort nach fscanf(...) der Befehl 
fprintf(..) benutzt werden (und umgekehrt) , sondern es muss zuerst
noch fseek(...) gemacht werden, also: 
fscanf(...); fseek(...); fprintf(...);

3) Man kann sich die oben erstellte Datei mit einem beliebigen
Texteditor anschauen, indem man diese z.B. mit Doppelklick öffnet,
oder mit MS VC++ eine Datei im Modus "Binär" öffnen.

4) Es gibt auch Funktionen, die sich auf Dateien als Ganzes 
beziehen, wie z.B. Datei löschen (remove), 
Dateien umbenennen (rename), Dateigröße ändern ( _chsize).
*/
