![]() |
Einfaches Abspeichern in externer Datei // Schülerverwaltung
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
ich bin gerade dabei ein Programm zu schreiben, mit dessen Hilfe ich Schülerdaten (Schülernr., Name, Vorname, Klasse, usw.) in einer Datei abspeichern kann, sodass diese nach Schließen und erneutem Öffnen des Programms über den Klick eines Buttons wieder eingelesen werden und wieder verfügbar sind. Soweit so gut. Allerdings werden, wenn ich Daten zu verschiedenen Schülern gespeichert habe, und mich vergewissert habe, dass diese auch wieder über die Schülernummer aufrufbar sind, diese nicht geladen bzw. wieder korrekt ausgegeben, wenn ich das Programm neustarte. Ich würde mich sehr freuen, wenn ihr mich ein bisschen bei der Fehlersuche unterstützen könntet. Im Unterricht wurden uns jedenfalls heute einfach diese ganzen assignfile-Sachen an den Kopf geknallt. Der Test auf IO-Fehler ist übrigens ein Pflichtelement des Programms. Hier mal der Quelltext:
Delphi-Quellcode:
Im Anhang habe ich noch mal ein Bild, das zeigt, wie das Programm so aussieht.
unit zeugnis;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) ButtonSpeichern: TButton; ButtonAuslesen: TButton; ButtonBeenden: TButton; EditSNr: TEdit; EditName: TEdit; EditVorname: TEdit; EditGebDat: TEdit; EditGebOrt: TEdit; EditOrt: TEdit; EditKlasse: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; Label9: TLabel; ButtonClear: TButton; EditDatensatzNr: TEdit; Label10: TLabel; ButtonSchuelerDaten: TButton; Label11: TLabel; ButtonEintragSpeichern: TButton; procedure ButtonBeendenClick(Sender: TObject); procedure ButtonSpeichernClick(Sender: TObject); procedure ButtonAuslesenClick(Sender: TObject); procedure ButtonClearClick(Sender: TObject); procedure ButtonSchuelerDatenClick(Sender: TObject); procedure ButtonEintragSpeichernClick(Sender: TObject); end; tSNr = string[5]; tName = string[20]; tVorname = string[15]; tGebDat = string[10]; tGebOrt = string[15]; tOrt = string[15]; tKlasse = string[4]; tSchueler = record Nr :tSNr; //Schuelernummer bzw. Datensatznummer Name :tName; //Schuelername Vorname :tVorname; //Schuelervorname Geburtsort :tGebOrt; //Geburtsort GebDat :tGebDat; //Geburtsdatum Ort :tOrt; //Wohnort Klasse :tKlasse; //Klasse end; const Datenpfad='Schueler.dta'; var Form1: TForm1; Datensatz: array[1..99999] of tSchueler; //Array für Schuelerdatensätze num: integer; //Datensatznummer f: file of tSchueler; implementation {$R *.dfm} procedure Kontrolle; //Prozedur zum Test, ob einige der bekannten IO-Fehler gefunden werden begin case IOResult of 2: begin showmessage ('Datei nicht vorhanden.' +#13+ 'Datei wird angelegt'); rewrite(f); closeFile(f); end; 3: showmessage ('Ungueltiger Dateiname/Pfad'); 5: showmessage ('Dateizugriff verweigert.'); 21: showmessage ('Laufwerk nicht bereit!'); end; end; procedure TForm1.ButtonSpeichernClick(Sender: TObject); //Datenbank abspeichern var i:integer; begin Assignfile (f,Datenpfad); {$I-} reset (f); {$T+} Kontrolle; if IOResult=0 then begin for i:=1 to 99999 do write (f, Datensatz[i]); closefile (f); end; end; procedure TForm1.ButtonAuslesenClick(Sender: TObject); //Datenbank laden var i:integer; begin Assignfile (f,Datenpfad); Kontrolle; if IOResult=0 then begin for i:=1 to 99999 do read (f, Datensatz[i]); closefile (f); end; end; procedure TForm1.ButtonEintragSpeichernClick(Sender: TObject); //Schüler-Eintrag speichern var fehler: boolean; //Wird true gesetzt, wenn ein Eingabefeld leer ist begin fehler:=false; num:=1; if length(EditSNr.Text)=0 then fehler:=true else begin num:=StrToInt(EditSNr.Text); if length(EditSNr.Text)<>0 then Datensatz[num].Nr:= EditSNr.Text else fehler:=true; if length(EditName.Text)<>0 then Datensatz[num].Name:= EditName.Text else fehler:=true; if length(EditVorname.Text)<>0 then Datensatz[num].Vorname:= EditVorname.Text else fehler:=true; if length(EditGebOrt.Text)<>0 then Datensatz[num].Geburtsort:= EditGebOrt.Text else fehler:=true; if length(EditGebDat.Text)<>0 then Datensatz[num].GebDat:= EditGebDat.Text else fehler:=true; if length(EditOrt.Text)<>0 then Datensatz[num].Ort:= EditOrt.Text else fehler:=true; if length(EditKlasse.Text)<>0 then Datensatz[num].Klasse:= EditKlasse.Text else fehler:=true; end; if fehler=true then showmessage('Bitte füllen Sie alle Felder aus!') else begin showmessage('Eintrag erfolgreich gespeichert'); end; end; procedure TForm1.ButtonClearClick(Sender: TObject); //Felder leeren begin EditSNr.Text:=''; EditName.Text:=''; EditVorname.Text:=''; EditGebOrt.Text:=''; EditGebDat.Text:=''; EditOrt.Text:=''; EditKlasse.Text:=''; end; procedure TForm1.ButtonSchuelerDatenClick(Sender: TObject); //Daten zu einem Schüler anzeigen var i: integer; //Datensatznummer begin i:=StrToInt(EditDatensatzNr.Text); if (length(EditDatensatzNr.Text)<>0) and (length(EditDatensatzNr.Text)<=5) then begin EditSNr.Text:=Datensatz[i].Nr; EditName.Text:=Datensatz[i].Name; EditVorname.Text:=Datensatz[i].Vorname; EditGebOrt.Text:=Datensatz[i].GeburtsOrt; EditGebDat.Text:=Datensatz[i].GebDat; EditOrt.Text:=Datensatz[i].Ort; EditKlasse.Text:=Datensatz[i].Klasse; end else showmessage('Bitte eine gültige Datensatz-Nummer eintragen'); end; procedure TForm1.ButtonBeendenClick(Sender: TObject); //Programm beenden begin close; end; end. Vielen Dank Jan |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Guten Abend,
ich würde die Prozedure Kontrolle zu einer Funktion umbauen:
Delphi-Quellcode:
und sie dann so einsetzen:
function Kontrolle:Boolean; //Prozedur zum Test, ob einige der bekannten IO-Fehler gefunden werden
begin result := false; case IOResult of 0: result := true; 2: begin showmessage ('Datei nicht vorhanden.' +#13+ 'Datei wird angelegt'); rewrite(f); // closeFile(f); // wenn Du die Datei erstellt hast nicht gleich wieder schließen Du willst ja noch etwas abspeichern result := true; end; 3: showmessage ('Ungueltiger Dateiname/Pfad'); 5: showmessage ('Dateizugriff verweigert.'); 21: showmessage ('Laufwerk nicht bereit!'); end; end;
Delphi-Quellcode:
procedure TForm1.ButtonSpeichernClick(Sender: TObject); //Datenbank abspeichern
var i:integer; begin Assignfile (f,Datenpfad); {$I-} reset (f); {$I+} if Kontrolle then begin for i:=1 to 99999 do write (f, Datensatz[i]); closefile (f); end; end; denn in Deinem Konstrukt wird IOResult immer 0 sein. Denn wenn IOResult einmal abgefragt wurde wird IOError gelöscht: Aus der Hilfe: Zitat:
[edit]
Delphi-Quellcode:
hier vielleicht einen absoluten Pfad zur Datei angeben.
const Datenpfad='Schueler.dta';
[edit2]
Delphi-Quellcode:
procedure TForm1.ButtonAuslesenClick(Sender: TObject); //Datenbank laden
var i:integer; begin i:=1; Assignfile (f,Datenpfad); {$I-} reset(f) {$I+} if Kontrolle then begin while not eof(f) do begin read(f, Datensatz[i]); inc(i); end; end; closefile (f); end; end; Grüße Klaus |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Moin, Moin.
Delphi-Quellcode:
PS:
procedure TForm1.ButtonSpeichernClick(Sender:TObject);
var i : Integer; f : file of tSchueler; begin assignfile(f,Datenpfad); {$I-} rewrite (f); {$I+} .. procedure TForm1.ButtonLadenClick(Sender:TObject); var i : Integer; f : file of tSchueler; begin assignfile(f,Datenpfad); {$I-} reset (f); {$I+} .. a) So wenig wie möglich global deklarieren! b) "Datensatz: array[1..99999] of tSchueler;" ist schon heftig! Kennt ihr noch keine dynamischen Arrays? |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Hallo,
statt
Delphi-Quellcode:
würde ich
tSchueler = record
Delphi-Quellcode:
schreiben und die alte Datei löschen..
tSchueler = packed record
Ausserdem kannst du mit FileExists prüfen, ob die Datei vorhanden ist und dann entweder Reset oder ReWrite benutzen. Das ersetzt natürlich das IOResult nicht. Bei procedure TForm1.ButtonEintragSpeichernClick fiel mir noch was auf. Was passiert, wenn der letzte Editor leer ist ... Du hast alle anderen Werte schon in den Datensatz eingetragen und ereugst zum Schluss einen Fehler. Die anderen Werte stehen aber trotzdem schon drin ! Besser wäre hier
Delphi-Quellcode:
fehler:= (EditName.Text='') or
(EditOrt.Text='') or usw. (EditOrt.EditKlasse=''); Heiko |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Hallo Jan,
die wichtigste Antwort hat Dir wohl Klaus schon gegeben:
Delphi-Quellcode:
Bei Deiner Lösung (for i:=0 to 99999....) hast immer das Problem, daß eine teilweise beschädigte Datei das Lesen unmöglich macht.
while not eof(f) do
begin read(f, Datensatz[i]); inc(i); end; Mir behagt die Definition des records nicht
Delphi-Quellcode:
Ich würde mit fixen Satzlängen arbeiten:
tSNr = string[5];
tName = string[20]; tVorname = string[15]; tGebDat = string[10]; tGebOrt = string[15]; tOrt = string[15]; tKlasse = string[4]; tSchueler = record Nr :tSNr; //Schuelernummer bzw. Datensatznummer Name :tName; //Schuelername Vorname :tVorname; //Schuelervorname Geburtsort :tGebOrt; //Geburtsort GebDat :tGebDat; //Geburtsdatum Ort :tOrt; //Wohnort Klasse :tKlasse; //Klasse end;
Delphi-Quellcode:
Wobei allerdings ein leerer Datensatz und ein mit Leerzeichen gefüllter Datensatz nicht zu unterscheiden wären.
tSNr = Array of Char[1..5];
tName = Array of Char[1..20]; tVorname = Array of Char[1..15]; tGebDat = Array of Char[1..10]; tGebOrt = Array of Char[1..15]; tOrt = Array of Char[1..15]; tKlasse = Array of Char[1..4]; tSchueler = record Nr :tSNr; //Schuelernummer bzw. Datensatznummer Name :tName; //Schuelername Vorname :tVorname; //Schuelervorname Geburtsort :tGebOrt; //Geburtsort GebDat :tGebDat; //Geburtsdatum Ort :tOrt; //Wohnort Klasse :tKlasse; //Klasse end; (Ok da kann man noch eine #0 als Begrenzer einsetzen, verliert aber ein Datenzeichen) Wenn Du dann noch ein #13#10 als Abschluß Deines Records hinein packst, ist die Datei problemlos mit jedem Editor les- und kontrollierbar. Gruß K-H |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
@p80286: das sind ShortStrings und die haben immer eine fixe Größe :zwinker:
String[8] ist ein AnsiString mit maximal 8 Zeichen Inhalt, die Größe im Speicher liegt immer bei genau 9 Byte und im Gegensatz zu den "normalen" Strings gibt es hier keinen internen Pointer. |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
@himitsu
Pardon ungenau ausgedrückt. wenn Du z.B. "Ralf" abspeichern willst, dann steht hinterher in der Datei #4Ralfxxxxxxxxxxxxxx wobei jedes x für irgendein beliebiges Zeichen steht. Das ist bei meinem Vorschlag nicht der Fall, da ja jedes Feld vorher initialisiert wird/werden sollte.(Hab ich auch vergessen zu schreiben) Das es ein paar intelligentere Formate zum Abspeichern gibt, lassen wir mal aussen vor. Gruß K-H |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Hihi, genau diese Aufgabe hatte ich am Anfang meines Studiums auch auf dem Tisch liegen.
Statt deines Arrays würde ich eine doppelt verkettete Liste verwenden und beim Auslesen auf EOF prüfen. Die hat den Vorteil, dass du nicht gebunden bist. Aber ist Geschmackssache. |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Also einen ShortString kann man auch initialisieren, wenn man denn will.
|
Re: Einfaches Abspeichern in externer Datei
Sorry, dass ich mich nicht gemeldet habe.
Also ich habe mal versucht eure Vorschläge mit einzuarbeiten. Wenn ich jetzt allerdings auf das Feld "Datenbank Laden" klicke erhalte ich eine Fehlermeldung in neuem Fenster: "Project raised exception class EInOutError with message 'Read beyond end of file'. Process stopped. Use step or run to continue" So sieht mein Quelltext jetzt aus:
Delphi-Quellcode:
Ich habe noch nicht ganz verstanden, wie ihr das mit den dynamische Arrays meint. Ich habe jetzt erstaml aus Testzwecken die Schülerzahl auf 10 gesenkt.
unit zeugnis;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) ButtonSpeichern: TButton; ButtonAuslesen: TButton; ButtonBeenden: TButton; EditSNr: TEdit; EditName: TEdit; EditVorname: TEdit; EditGebDat: TEdit; EditGebOrt: TEdit; EditOrt: TEdit; EditKlasse: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; Label9: TLabel; ButtonClear: TButton; EditDatensatzNr: TEdit; Label10: TLabel; ButtonSchuelerDaten: TButton; Label11: TLabel; ButtonEintragSpeichern: TButton; procedure ButtonBeendenClick(Sender: TObject); procedure ButtonSpeichernClick(Sender: TObject); procedure ButtonAuslesenClick(Sender: TObject); procedure ButtonClearClick(Sender: TObject); procedure ButtonSchuelerDatenClick(Sender: TObject); procedure ButtonEintragSpeichernClick(Sender: TObject); end; tSNr = string[5]; tName = string[20]; tVorname = string[15]; tGebDat = string[10]; tGebOrt = string[15]; tOrt = string[15]; tKlasse = string[4]; tSchueler = record Nr :tSNr; //Schuelernummer bzw. Datensatznummer Name :tName; //Schuelername Vorname :tVorname; //Schuelervorname Geburtsort :tGebOrt; //Geburtsort GebDat :tGebDat; //Geburtsdatum Ort :tOrt; //Wohnort Klasse :tKlasse; //Klasse end; const Datenpfad='Schueler.dta'; var Form1: TForm1; Datensatz: array[1..10] of tSchueler; //Array für Schuelerdatensätze f: file of tSchueler; implementation {$R *.dfm} function Kontrolle:Boolean; //Prozedur zum Test, ob einige der bekannten IO-Fehler gefunden werden begin result := false; case IOResult of 0: result := true; 2: begin showmessage ('Datei nicht vorhanden.' +#13+ 'Datei wird angelegt'); rewrite(f); result := true; end; 3: showmessage ('Ungueltiger Dateiname/Pfad'); 5: showmessage ('Dateizugriff verweigert.'); 21: showmessage ('Laufwerk nicht bereit!'); end; end; procedure TForm1.ButtonSpeichernClick(Sender: TObject); //Datenbank abspeichern var i:integer; begin Assignfile (f,Datenpfad); {$I-} reset (f); {$I+} if Kontrolle then begin for i:=1 to 10 do write (f, Datensatz[i]); closefile (f); end; end; procedure TForm1.ButtonAuslesenClick(Sender: TObject); //Datenbank laden var i:integer; begin i:=1; Assignfile (f,Datenpfad); {$I-} reset(f); {$I+} if Kontrolle then begin while not eof(f) do begin read(f, Datensatz[i]); inc(i); end; end; closefile (f); end; procedure TForm1.ButtonEintragSpeichernClick(Sender: TObject); //Schüler-Eintrag speichern var fehler: boolean; //Wird true gesetzt, wenn ein Eingabefeld leer ist i:integer; begin fehler:=false; i:=1; if length(EditSNr.Text)=0 then fehler:=true else begin i:=StrToInt(EditSNr.Text); if length(EditSNr.Text)<>0 then Datensatz[i].Nr:= EditSNr.Text else fehler:=true; if length(EditName.Text)<>0 then Datensatz[i].Name:= EditName.Text else fehler:=true; if length(EditVorname.Text)<>0 then Datensatz[i].Vorname:= EditVorname.Text else fehler:=true; if length(EditGebOrt.Text)<>0 then Datensatz[i].Geburtsort:= EditGebOrt.Text else fehler:=true; if length(EditGebDat.Text)<>0 then Datensatz[i].GebDat:= EditGebDat.Text else fehler:=true; if length(EditOrt.Text)<>0 then Datensatz[i].Ort:= EditOrt.Text else fehler:=true; if length(EditKlasse.Text)<>0 then Datensatz[i].Klasse:= EditKlasse.Text else fehler:=true; end; if fehler=true then showmessage('Bitte füllen Sie alle Felder aus!') else begin showmessage('Eintrag erfolgreich gespeichert'); end; end; procedure TForm1.ButtonClearClick(Sender: TObject); //Felder leeren begin EditSNr.Text:=''; EditName.Text:=''; EditVorname.Text:=''; EditGebOrt.Text:=''; EditGebDat.Text:=''; EditOrt.Text:=''; EditKlasse.Text:=''; end; procedure TForm1.ButtonSchuelerDatenClick(Sender: TObject); //Daten zu einem Schüler anzeigen var i: integer; //Datensatznummer begin i:=StrToInt(EditDatensatzNr.Text); if (length(EditDatensatzNr.Text)<>0) and (length(EditDatensatzNr.Text)<=5) then begin EditSNr.Text:=Datensatz[i].Nr; EditName.Text:=Datensatz[i].Name; EditVorname.Text:=Datensatz[i].Vorname; EditGebOrt.Text:=Datensatz[i].GeburtsOrt; EditGebDat.Text:=Datensatz[i].GebDat; EditOrt.Text:=Datensatz[i].Ort; EditKlasse.Text:=Datensatz[i].Klasse; end else showmessage('Bitte eine gültige Datensatz-Nummer eintragen'); end; procedure TForm1.ButtonBeendenClick(Sender: TObject); //Programm beenden begin close; end; end. Vielen Dank im Voraus Jan |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Du hast ein statisches Array mit 10 Elementen deklariert.
Zitat:
Delphi-Quellcode:
Die Länge setzt Du mit SetLength fest, dadurch wächst/schrumpft das Array dynamisch. Somit bist Du flexibler.
Datensatz: array of tSchueler;
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Aber woher weiß ich denn welche Zahl ich am Ende von setlength eintragen muss? Kann ich irgendwie ersehen, welches die höchste Datennummer ist und das dann als Ende eintragen?
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Die aktuelle Länge des Array bekommst Du mit Length. Um also ein Element anzufügen, kannst Du das so machen(Pseudocode):
Delphi-Quellcode:
Löschen des letzten Elements geht dann logischerweise mit
SetLength(Array, Length(Array) + 1);
Array[High(Array)] := Daten;
Delphi-Quellcode:
SetLength(Array, Length(Array) - 1);
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Okay, werde ich gleich mal versuchen einzubauen.
Hat noch jemand eine Idee, warum es zu der Fehlermeldung kommt? |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
In welcher Zeile tritt der Fehler auf?
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
In der Zeile:
read(f, Datensatz[i]); in der Prozedur zum auslesen. |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Entweder ist es schon zu spät, ich bin blind oder der Fehler liegt irgendwo anders. Für mich sieht der Code OK aus :gruebel:
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Mhmm, es scheint jetzt zu funktionieren. Ich habe mal die alte 8 Megabyte Große Datei Schueler.dta gelöscht. Sie wurde vom Programm neu angelegt und der Fehler tritt nicht mehr auf...
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
War der Record evtl. vorher mit einer anderen Größe deklariert? Das wäre zumindest eine Erklärung.
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Naja, mein Array war ja vorher auf 99999^^
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Ich meine nicht das Array, sondern den Record. Ist da ein Feld hinzugekommen oder rausgeflogen oder in der Größe geändert worden?
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Eigentlich nicht...
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Hallo,
hast du das mit dem packed record gemacht ? Das wäre auch eine Erklärung. Heiko |
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Nein...
|
Re: Einfaches Abspeichern in externer Datei // Schülerverwal
Ist aber auch jetzt egal, irgendetwas wird es schon gewesen sein.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:55 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz