Entwickler-Ecke

Dateizugriff - Binärbaum in Datei speichern


mithos - Mo 22.02.10 20:38
Titel: Binärbaum in Datei speichern
Hallo
ich habe eine Frage dazu, wie ich einen Binärbaum, der Zahlen enthält, in eine Datei speichern kann.
Ja, es sind Hausaufgaben, allerdings brauche ich nur mal einen Stoß in die richtige Richtung. Das Wiederherstellen des Baumes ist auch Teil der Aufgabe, allerdings bin ich ehrlich gesagt schon froh, wenn ich das Speichern hinkriege.

Die eine Liste der Dateioperationen haben wir bekommen, allerdings weiß ich nicht, wie genau ich jene benutzen soll.



Delphi-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:
procedure tBaum.toDatei;
var F:file of integer;
    daten, datei : string;


   {
   procedure AssignFile(var F:file; Datei:string);
   begin
     AssignFile(F,Datei);
   end;

   procedure Rewrite(var F:file);
   begin
     Rewrite(F);
   end;

   procedure CloseFile(var F:file);
   begin
     CloseFile(F);
   end;
   }


begin
  AssignFile(F, Datei);
  Rewrite(F);
  daten := inorder;
  Readln(daten);
  WriteLn(F, daten);

  CloseFile(F);
end;



Inorder ist eine Funktion, die als Rückgabewert einen String mit allen Knoten zurückgibt.

Der auskommentierte Teil war zuerst noch drin, das war mein 1. Versuch, die Dateioperationen anzuwenden :/
In welcher Form muss ich diese denn nun anweden? Reicht es, einfach nur
AssignFile(F, Datei);
anstatt

Delphi-Quelltext
1:
procedure AssignFile(var F:file; Datei:string);                    

anzugeben? Wenn nein, muss ich noch etwas in diese Prozedur reinschreiben?

Delphi selbst gibt jetzt als Fehlermeldung nur aus: [Pascal Fehler] mTBinBaum.pas(374): E2054 Ungültiger Typ in Write/Writeln-Anweisung

'daten' ist ja auch ein string, wohingegen das file vom Typ Integer sein soll. Ich habe aber keine Ahnung, wie ich Zahlen in die Datei schreiben soll. Über Google habe ich eben nur den write Befehl gefunden, der aber wohl nur für strings ist.



Bin für alle Tipps dankbar.
Gruß


bole - Mo 22.02.10 21:52

Hallo mithos

Willkommen im Forum! :welcome:

Die Proceduren Assignfile, Closefile... die Du in Kommentar gesetzt hast kannst Du löschen, das sind Befehle.

Bei dem Befehl Assignfile musst Du als zweiten Parameter einen kompletten Dateinamen angeben. Komfortabler ist es mit dem TSaveDialog (siehe Hilfe / Suche im Forum)

Dein Problem beim speichern ist aber das Du zuviel auf einmal willst! Das speichern musst Du pro Knoten machen und nicht alle mitteinander. Ich nehme an deine Inorder Funktion besteht aus etwa 3 rekursiven aufrufen. Statt dir einen grossen String aus den Knoten zusammenzubasteln musst du sie jeweils auf in das File speichern.

Ich würde die Befehle der Funktion Inorder in die Speicherprocedure kopieren.


mithos - Mo 22.02.10 22:13

Hallo bole und danke für deine Antwort!

Ich habe deine Ratschläge versucht umzusetzen. Meine Prozedur sieht nun folgendermaßen aus:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
procedure tBaum.toDatei;
var F:file of integer;

  procedure inorder_rek(knoten : TKnoten);
  begin
     if not (knoten = nilthen
       begin
          inorder_rek(knoten.links);
          WriteLn(F, knoten.inhalt);
          inorder_rek(knoten.rechts);
       end;
  end;


begin
  AssignFile(F, 'Desktop:\binBaumSaveLoad.txt');
  Rewrite(F);

  inorder_rek(wurzel);

  CloseFile(F);
end;



Wenn ich versuche, zu compilieren, erscheint die folgende Fehlermeldung: [Pascal Fehler] mTBinBaum.pas(355): E2054 Ungültiger Typ in Write/Writeln-Anweisung zu der Zeile

Delphi-Quelltext
1:
WriteLn(F, knoten.inhalt);                    

Kommt die Fehlermeldung daher, dass ich nur strings mit Writeln schreiben kann? Wie kann ich sonst Zahlen in eine Datei schreiben, gibt es dafür einen anderen Befehl?

Vielen Dank schon mal bis hierhin.
Gruß


bole - Mo 22.02.10 22:23

Du hast eine Idee zur Lösung... hast Du die probiert?

Interessant wäre wie Du TKnoten definiert hast, ist Knoten.inhalt vom Typ Integer?

Du schreibst auch im Assignfile ein File mit der Endung .txt; Für Delphi ist das kein Problem aber mit den Notepad kann man dieses nicht wirklich lesen...

GRuss

Bole


mithos - Mo 22.02.10 22:42


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
TInhalt = integer;

TKnoten = class
  private
    inhalt: TInhalt;
    links,rechts: TKnoten;
    constructor create(inhalt : TInhalt);
  public
    function gibLinks : tKnoten;
    function gibRechts : tKnoten;
    function gibInhalt : TInhalt;
end;


Also ja, inhalt ist vom Typ integer.

Ich habe eben gerade etwas per Google gefunden bezüglich des write Befehls, allerdings hilft mir das nicht weiter:

Delphi-Quelltext
1:
2:
3:
// Write some numbers to the file as a single line
  for i := 2 to 4 do
    Write(myFile, i/2'  ');

hier scheint das ja zu klappen, mit dem write Befehl auch Zahlen zu schreiben, wieso klappt das bei mir nicht? *ratlos*


Noch eine Frage zum zweiten Aufgabenteil, in dem gefordert ist, die integer Werte auch wieder aus der Datei zu lesen und in den Baum einzufügen.
Das Problem ist, dass ich nicht einfach die Werte nacheinander lesen und wieder einfügen kann, da dies zu einem Baum führen würde, der zu einer Liste entartet ist, da ich ja inorder eingelesen habe. Theoretisch kann ich aber einfach preorder die Knoten lesen und in die Datei schreiben. Dadurch kann ich dann auch einfach die Werte nacheinander lesen und wieder einfügen und ich erhalte den selben Baum, richtig?


bole - Mo 22.02.10 22:59

Der Variable knoten.inhalt ist nicht vom Typ integer sondern vom Typ TInhalt. TInhalt macht meines erachtens nicht viel Sinn, es ist ja einfach ein integer. Definiere inhalt als integer statt als TInhalt.


mithos - Mo 22.02.10 23:17

Habe TInhalt rausgenommen, und es überall durch integer ersetzt, kriege aber immernoch die selbe Fehlermeldung..
Habe inorder zu preorder verändert, der Prozedurteil sieht nun so aus:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
  procedure preorder_rek(knoten : TKnoten);
  begin
     if not (knoten = nilthen
       begin
          WriteLn(F, knoten.inhalt);
          preorder_rek(knoten.links);
          preorder_rek(knoten.rechts);
       end;
  end;


in TKnoten habe ich inhalt als integer definiert


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
TKnoten = class
  private
    inhalt: integer;
    links,rechts: TKnoten;
    constructor create(inhalt : integer);
  public
    function gibLinks : tKnoten;
    function gibRechts : tKnoten;
    function gibInhalt : integer;
end;



Fehlermeldungen
[Pascal Fehler] mTBinBaum.pas(354): E2054 Ungültiger Typ in Write/Writeln-Anweisung und
[Pascal Fehler] mTBinBaum.pas(354): E2008 Inkompatible Typen


Weiterhin erhalte ich bei

Delphi-Quelltext
1:
Reset(F);                    

ain meiner anderen Prozedur zum Schreiben in den Baum die Fehlermeldung [Pascal Fehler] mTBinBaum.pas(378): E2034 Zu viele Parameter.
Reicht es denn, in der anderen Prozedur nur Reset(F); aufzurufen? AssignFile wird ja nur einmal benötigt und das habe ich ja in der anderen Prozedur..?

Danke
Gruß


bole - Di 23.02.10 00:14

Hast Du mal die Hilfe von Writeln gelesen?

'WriteLn ist eine Erweiterung der Prozedur Write , die für Textdateien definiert ist.'

Writeln funktioniert nicht nimm Write!

Kleine Frage am Rande: Dein Binärer Baum funktioniert mit Bildschirmausgaben (z.B. in Memo Feld?) Wenn nicht, ist das der erste Schritt den es zu korrigieren gibt.

Ich habe gesehen Du hast eine rekursive Definition:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TKnoten = class
  private
    inhalt: integer;
    links,rechts: TKnoten;
    constructor create(inhalt : integer);
  public


Ob dies geht oder nicht würde micht interessieren, ich kommen von der strukturierten Programierung, da hat man classen sondern Records und Pointer definiert... Ich nehme an links und rechts sollten auch eher Pointer auf TKnoten sein.

Poste doch mal Dein ganzes Projekt, aber leider komme ich heute und wahrscheinlich morgen nicht dazu das anzuschauen. Aber vielleicht findet sich ja jemand anders der Dir schneller Hilft

gruss
bole


Narses - Di 23.02.10 00:41

Moin!

user profile iconbole hat folgendes geschrieben Zum zitierten Posting springen:
Ich habe gesehen Du hast eine rekursive Definition:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
TKnoten = class
  private
    inhalt: integer;
    links,rechts: TKnoten;
    constructor create(inhalt : integer);
  public


Ob dies geht oder nicht würde micht interessieren, ich kommen von der strukturierten Programierung, da hat man classen sondern Records und Pointer definiert... Ich nehme an links und rechts sollten auch eher Pointer auf TKnoten sein.
Das ist schon OK so, Klassenreferenzen sind sowieso Pointer, aber eben typisierte. :idea: ;)

cu
Narses


mithos - Di 23.02.10 10:20

Oh, da war der Fehler also mit dem Write, vielen Dank :wink:


Das Programm liest eine Eingabe aus einem Feld in den Baum, welchen es auch graphisch darstellt.

Soweit ist alles gelöst, das einzige, was immer noch nicht geht, ist das Reset(F), da gibt er mir immer [Pascal Fehler] mTBinBaum.pas(378): E2034 Zu viele Parameter
als Fehlermeldung.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure tBaum.fromDatei;
var F:file of integer;
    KnInhalt: integer;

begin

  Reset(F);
  while not eof(F) do
  begin
    Read(F, KnInhalt);
    FuegeEin(KnInhalt);
  end;

  CloseFile(F);
end;


Danke und schönen Gruß


Tilman - Di 23.02.10 20:00

Also das Reset(F) sollte korrekt sein, aber du musst davor noch mit AssignFile die Datei öffnen.


mithos - Di 23.02.10 21:05

Ich erhalte immer noch die selbe Fehlermeldung, auch wenn ich das Assignfile nochmal reinnehme.
Da werd ich wohl meinen Informatiklehrer in der nächsten Stunde mal zu Rate ziehen müssen.
Wenn noch jemand eine Idee hat, warum diese Fehlermeldung auftritt, kann er sich ja nochmal hier melden, ansonsten hab ich die Hilfe, die ich gesucht habe, bekommen.
Vielen Dank :)
Gruß


Horst_H - Mi 24.02.10 09:23

Hallo,

ich hatte früher eher Ärger mit EOF(F).
Ein File of DatenTyp hat aber den Vorteil, dass man, im Gegesatz zu Textdateien, die Größe abfragen kann.
http://www.delphibasics.co.uk/ByUnit.asp?Unit=System und dort http://www.delphibasics.co.uk/RTL.asp?Name=FileSize


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
procedure tBaum.fromDatei;
var F:file of integer;
    KnInhalt: integer;
    i : integer;
begin
  AssignFile(F, 'Desktop:\binBaumSaveLoad.txt');
  Reset(F);
  For i := 1 to fileSize(F) do
  begin
    Read(F, KnInhalt);
    FuegeEin(KnInhalt);
  end;

  CloseFile(F);
end;


Gruß Horst
P.S.
O.K Bei Textdateien und untypisierten Dateien wird mit einer Größe von Datentyp von 128 Byte gerechnet
http://www.delphibasics.co.uk/RTL.asp?Name=Reset ausser man benutzt Reset mit dem Zusatz der Datentypgröße bei untypisierten Dateien