Datenspeicherung allgemein
-
- Beiträge: 36
- Registriert: Di 31. Jan 2017, 17:18
Datenspeicherung allgemein
Hallo zusammen !
Ich mal wieder mit einem Problem.
Nachdem ich nun ein Buch zu Lazarus habe (von Wilfred Koch) bin ich dann auch gleich dazu übergegangen mich mit dem Abspeichern und Einlesen von Daten zu befassen.
Streng nach Lehrbuch habe ich nachstehenden Code geschrieben :
. Unit Unit1;
. uses
. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ActnList,
. StdCtrls;
. type
. Type_PLZ_Stadt = record
. Record_PLZ : Integer;
. Record_Stadt : String;
. end;
.
. File_PLZ_Stadt = file of Type_PLZ_Stadt;
.
. { TGrundform }
. TGrundform = class(TForm)
. PLZ : TEdit;
. Stadt : TEdit;
. Lesen: TButton;
. Speichern: TButton;
.
. private
. { private declarations }
. public
. { public declarations }
. end;
.
. Procedure Datensatz_sichern;
. Procedure Datensatz_holen;
.
. var
.
. Grundform: TGrundform;
. PfadPLZ_Stadt : String = 'C:/CTS-Soft/Dateien/PLZ_Stadt.dat';
. PLZ_Stadt : Type_PLZ_Stadt;
. DPLZ_Stadt : File_PLZ_Stadt;
. DSatz : Integer = 0;
.
. implementation
.
. {$R *.lfm}
Soweit so schön und die Deklaration ist auch so wie im Buch.
Beim Kompilieren jedoch meckert der Compiler die oben rot markierte Zeile an (hervorgehoben der Eintrag "Type_PLZ_Stadt") mit der Meldung :
Projekt kompilieren, Ziel: C:\Users\Bernhard\AppData\Local\Temp\project1.exe: Exit code 1, Fehler: 1
unit1.pas(18,42) Error: Typed files cannot contain reference-counted types.
Ich kann damit leider nichts anfangen.
Kann mir jemand auf die Sprünge helfen ???
Bernhard
Ich mal wieder mit einem Problem.
Nachdem ich nun ein Buch zu Lazarus habe (von Wilfred Koch) bin ich dann auch gleich dazu übergegangen mich mit dem Abspeichern und Einlesen von Daten zu befassen.
Streng nach Lehrbuch habe ich nachstehenden Code geschrieben :
. Unit Unit1;
. uses
. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ActnList,
. StdCtrls;
. type
. Type_PLZ_Stadt = record
. Record_PLZ : Integer;
. Record_Stadt : String;
. end;
.
. File_PLZ_Stadt = file of Type_PLZ_Stadt;
.
. { TGrundform }
. TGrundform = class(TForm)
. PLZ : TEdit;
. Stadt : TEdit;
. Lesen: TButton;
. Speichern: TButton;
.
. private
. { private declarations }
. public
. { public declarations }
. end;
.
. Procedure Datensatz_sichern;
. Procedure Datensatz_holen;
.
. var
.
. Grundform: TGrundform;
. PfadPLZ_Stadt : String = 'C:/CTS-Soft/Dateien/PLZ_Stadt.dat';
. PLZ_Stadt : Type_PLZ_Stadt;
. DPLZ_Stadt : File_PLZ_Stadt;
. DSatz : Integer = 0;
.
. implementation
.
. {$R *.lfm}
Soweit so schön und die Deklaration ist auch so wie im Buch.
Beim Kompilieren jedoch meckert der Compiler die oben rot markierte Zeile an (hervorgehoben der Eintrag "Type_PLZ_Stadt") mit der Meldung :
Projekt kompilieren, Ziel: C:\Users\Bernhard\AppData\Local\Temp\project1.exe: Exit code 1, Fehler: 1
unit1.pas(18,42) Error: Typed files cannot contain reference-counted types.
Ich kann damit leider nichts anfangen.
Kann mir jemand auf die Sprünge helfen ???
Bernhard
Re: Datenspeicherung allgemein
Das Beispiel funktioniert nur, wenn du Strings verwendest, die als ShortString definiert sind. Diese enthalten dann eine feste Größe bis maximal 255 Zeichen: http://wiki.freepascal.org/Character_an ... hortString
Also entweder so:
oder du stellst per Compilerswitch um, daß für Strings, ShortStrings verwendet werden:
Also entweder so:
Code: Alles auswählen
unit Unit1;
{$mode objfpc}{$H+}
...
type
Type_PLZ_Stadt = record
Record_PLZ : Integer;
Record_Stadt : ShortString;
end;
File_PLZ_Stadt = file of Type_PLZ_Stadt;
Code: Alles auswählen
unit Unit1;
{$mode objfpc}{$H-} // mit $H- ist String = ShortString
...
type
Type_PLZ_Stadt = record
Record_PLZ : Integer;
Record_Stadt : String;
end;
File_PLZ_Stadt = file of Type_PLZ_Stadt;
Code: Alles auswählen
type
TLiveSelection = (lsMoney, lsChilds, lsTime);
TLive = Array[0..1] of TLiveSelection;
-
- Beiträge: 2120
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Datenspeicherung allgemein
Dynamische Arrays und Dynamische Strings können nicht einfach so gesichert werden. Hier mal das Kapitel über Dateien aus meinem Pascal Tutorial bei dem ich im letzen abschnitt genau darauf eingehe (rechtschreibfehler sind gratis):
Das letzte Kapitel zum Klassischen Pascal geht um das Thema Dateien. Wie Bekannt sein sollte Speichert der Computer Informationen dauerhaft in Form von Dateien in einem Dateisystem. Dabei hat jede Datei einen Namen, und einen Pfad zu dem Ordner der die Datei enthält. Je nach Betriebsystem unterscheidet sich die Darstellung von Dateiname und Pfad. Windows z.B. stellt jedes Speichermedium als Laufwerk da, welches mit einem Buchstaben und einem Doppelpunkt gekennzeichnet ist (C:, E:, D:), und dann mit Backslashes getrennt die Ordnerstruktur des Pfades, und am Ende der Dateiname, z.B.Unix Systeme hingegen Haben ein so genanntes Root Directory, der Basispfad des Speichermediums auf dem das System Installiert ist, und weitere Speichermedien werden als Ordner in diese Struktur eingehängt. Die Darstellung beginnt mit einem Slash, und darauf werden alle Ordner mit Slashes getrennt und am Ende folgt der Dateiname. Z.B:Code: Alles auswählen
C:\Pfad\Zur\Datei.ext
Zur Kategoriesierung der Dateien werden u.a. Dateiendungen verwendet, welche mit einem Punkt getrennt an den Dateinamen angehängt werden (um Beispiel .ext). Es gibt keine wirklichen Vorgaben an die Dateiendungen, und die können auch theoretisch beliebig verwendet werden, allerdings wird meißt eine aussagekräftige Abkürzung für den Dateiinhalt verwendet. So steht z.B. .txt für Textdateien, .exe für Windows Executeables, und .bmp für Bitmap.Code: Alles auswählen
/Pfad/Zur/Datei.ext
Konvention: Bei dem schreiben von eigenen Dateieformaten sollte man eine vernünftige Dateiendung wählen, so behält man selbst, oder andere die sich die Programme ansehen einen Überblick darüber was für ein Inhalt sich hinter einer Datei verbirgt. Meißt werden zur nomenklatur 3-4 Buchstaben lange Abkürzungen englischer Wörter verwendet wie .bin für binäre Dateien, .lst für Listen, .cfg für Konfigurationsdateien. Man sollte auch versuchen keine Etablierten Dateiendungen zu verwenden (wie .jpg für Textdokumente).
Dateitypen und Aufbau
Grundsätzlich unterscheiden wir zwischen zwei Typen von Dateien, Textdateien und Binärdateien, da diese sich im Umgang unterscheiden.
Textdateien sind Dateien mit für Menschen lesbaren Buchstaben. Textdateien werden entweder Zeilenweise, Wort für Wort, oder jeder Charakter einzeln gelesen.
Binärdateien hingegen werden Byteweise beschrieben. In Binärdateien werden die Werte in dem selben Byteformat wie die Pascal Datentypen gespeichert.
Da Binäredatentypen im gegensatz zu Textdateien nicht über einen einfachen Syntaxcheck verifiziert werden können, und die Bytes in verschiedenen Datentypen komplett andere Werte hat, verwendet man einen Header, um Informationen über den Inhalt zu stellen. Als Teil dieses Headers verwendet man oftmals eine so genannte Magic Number, eine Zahl, die den Datentypen Beschreibt. Wenn die Magic Number nicht der erwartete Wert ist weiß man dass es nicht der richtige Datentyp ist. Im Umkehrschluss kann man, bei mehreren Dateien mit gleicher Dateiendung über die Magic Number feststellen was der Inhalt dieser Dateien ist.
Pascal kennt außerdem noch Typisierte Binärdateien, das sind Binärdateien die nur einen Datentypen enthalten können, z.B. nur Integer Werte.
Dateien in Pascal
Um Dateien zu verwenden nutzt man in Pascal so genannte File Handles, das sind Betriebsystem interne Kennnummern für die geöffneten Dateien. Der Variablentyp für ein solches Dateihandle ist:
TextFile für Textdateien
File of Typ für typisierte Binärdateien
File für untypisierte Binärdateien.
Egal welcher Art, die Dateihandles bekommt man via AssignFile, muss sie mit CloseFile wieder Freigeben.
Genau wie bei Zeigern empfiehlt sich hier die Nutzung eines Try-Finally Blocks.Mit dem AssignFile wird das Handle zugewiesen, danach muss die Datei allerdings noch geöffnet werden. Das öffnen geschieht über Reset, Rewrite oder Append.Code: Alles auswählen
var F: TextFile; begin AssignFile(F, 'Pfad/Zur/Datei.ext'); try finally CloseFile(F); end; end;
Append ist zum Schreiben am Ende von Textdateien, also zum Anhängen von Texten. Rewrite erstellt eine neue Datei, exsistiert die Datei bereits wird sie überschrieben. Reset öffnet Textdateien zum lesen, oder Binärdateien zum Lesen und/oder Schreiben.
Nun gehe ich näher auf die einzelnen Typen ein.
Textdateien
Textdateien ließt und schreibt man genau wie mit der Konsole. Man verwendet Read und ReadLn bzw Write und WriteLn:Am besten erklärt das ein Beispiel Code:Code: Alles auswählen
Read(FileHandle, Variable); // Lese Inhalt von FileHandle in Variable ReadLn(FileHandle, Variable); // Lese eine Zeile in Variable Write(FileHandle, Wert); // Schreibt Wert in die Textdatei WriteLn(FileHandle, Wert); // Schreibt Wert+Zeilenumbruch in Textdatei
Dieses Programm sichert einen String, einen Integer und einen Double Zeilenweise in einer Textdatei und ließt diese anschließend wieder aus. Der Dateiinhalt ist mit 123 als Integer, String als String und 3.5 als Double dann:Code: Alles auswählen
program ReadText; {$Mode ObjFPC}{$H+} var F: TextFile; i: Integer; s: String; d: Double; begin // Variablen über Konsole einlesen ReadLn(i); ReadLn(s); ReadLn(d); AssignFile(F, 'datei.txt'); try Rewrite(F); // Zeilenweise Informationen Schreiben WriteLn(F, i); WriteLn(F, s); WriteLn(F, d); finally CloseFile(F); end; // Daten Lesen AssignFile(F, 'datei.txt'); try Reset(F); // Zeilenweise auslesen ReadLn(F, i); ReadLn(F, s); ReadLn(F, d); finally CloseFile(F); end; // Daten Ausgeben WriteLn(i); WriteLn(s); WriteLn(d); end.
Viel zu beachten gibt es an dieser Stelle eher nicht, da wir diese Form des Lesen und Schreiben schon von der Konsole kennen.Code: Alles auswählen
123 String 3.5000000000000000E+000
Typisierte Binärdateien
Bei Typisierten Binärdateien gibt man bei der Definition der Handle Variable einen Datentypen an, je nach dem was der Inhalt der Datei sein soll.
Binäre Dateien kann man mittels Reset in verschiedenen Modi öffnen. Dafür stellt Pascal die Globale Variable FileMode bereit. Diese kann man vor dem verwenden von Reset auf 3 verschiedene Werte setzen:Um die Datei entsprechend zum Lesen, Schreiben oder beidem zu öffnen.Code: Alles auswählen
fmOpenRead = 0 fmOpenWrite = 1 fmOpenReadWrite = 2
Wenn man eine Datei zum Schreiben öffnet, ohne die entsprechende Berechtigung im System zu haben wirft dies einen Fehler.
Hinweis: Wenn man die Variable FileMode nicht setzt so wird die Datei mit dem Default Modus fmOpenReadWrite geöffnet.
Bei typisierten binären Dateien werden Informationen via Read und Write geschrieben.
In dem folgenden Beispiel wird ein Record in eine Binärdatei geschrieben:Bemerkung: In diesem Beispiel verwende ich ShortString, da ShortStrings als statisch zusammengesetze Datenstruktur sich einfach Byteweise sichern lassen. Bei Dynamischen Strings würde lediglich der Zeiger auf den String gesichert werden.Code: Alles auswählen
program BinFileTest; {$MODE ObjFPC}{$H+} uses SysUtils; type // Record der gesichert werden soll TMyRec = record MyInt1, MyInt2: Integer; MyStr: ShortString; MyDouble: Double; end; var // FileHandle F: File of TMyRec; // Record Variable Rec: TMyRec; begin // Record befüllen Rec.MyInt1 := 5; Rec.MyInt2 := 10; Rec.MyStr := 'Hallo Welt'; // ShortString statische zusammengesetze Struktur Rec.MyDouble := 3.5; // Datei öffnen AssignFile(F, 'Test.bin'); try Rewrite(F); // Record schreiben Write(F, Rec); finally CloseFile(F); end; // Record Löschen FillChar(Rec, SizeOf(Rec), #00); // Datei wieder öffnen AssignFile(F, 'Test.bin'); try // FileMode setzen FileMode := fmOpenRead; Reset(F); // Daten Lesen Read(F, Rec); finally CloseFile(F); end; // Daten Ausgeben WriteLn(Rec.MyInt1); WriteLn(Rec.MyInt2); WriteLn(Rec.MyStr); WriteLn(Rec.MyDouble); end.
Als Typen für diese Dateien kann man letztlich alles nehmen, außer Zeiger, Dynamische Arrays oder Dynamische Strings, da man damit nur den Zeiger Speichern würde, welcher beim nächsten Durchlauf natürlich nicht unbedingt der Selbe sein muss. Statische Arrays, ShortStrings, Records oder andere Ordinärypen lassen sich aber ohne Probleme speichern.
Untypisierte Binärdateien
Schlussendlich gibt es noch untypisierte Binärdateien. In diese kann man beliebige binäre Daten sichern.
Dafür übergibt man der Funktion Reset bzw. Rewrite neben dem FileHandle noch einen weiteren Parameter, RecordSize. Diese gibt an in wie großen Blöcken geschrieben bzw gelesen werden soll. Schreibt man z.B. nur Integer (4 Byte) und Double (8 Byte) in eine Datei kann man eine RecordSize von 4 Byte wählen. Will man z.B. Bytes, oder genaue Größen wie von Packed Records sichern sollte man eine RecordSize von 1 Byte wählen.
Gelesen und Geschrieben wird dann mit den Funktionen:Wobei WriteCount bzw. ReadCount Optionale Var Parameter sind. Buffer is auch ein Var Parameter, über welchen die Variable übergeben wird deren Inhalt geschrieben werden soll, oder in die gelesen werden soll. Count gibt an wie viele Einheiten der über Reset bzw. Rewrite RecordSize größe gelesen werden soll. Wenn eine Optionale Variable ReadCount bzw. WriteCount übergeben wird, wird dort gespeichert wie viele Einheiten tatsächlich gelesen wurden (im Fall dass man versucht mehr Bytes zu lesen als die Datei enthält).Code: Alles auswählen
BlockRead(FileHandle, Buffer, Count, ReadCount); BlockWrite(FileHandle, Buffer, Count, WriteCount);
Bemerkung: Will man größere Datenmengen in einen Array oder String laden, so empfiehlt sich die Elemente in größeren Blöcken (z.B. 1024 Bytes) zu lesen, und über ReadCount kann man dann überprüfen ob man am Ende der Datei angekommen ist.
Ein kleines Beispiel:Dabei wird ein Integer, ein Double und ein ShortString in die Binärdatei geschrieben.Code: Alles auswählen
program BinFileTest; {$MODE ObjFPC}{$H+} uses SysUtils; var F: File; i: Integer; s: ShortString; d: Double; begin i := 4; s := 'Hallo Welt'; d := 3.5; AssignFile(F, 'Test.bin'); try Rewrite(F, 1); // 1 Byte RecordSize BlockWrite(F, i, SizeOf(Integer)); // Integer Schreiben BlockWrite(F, s, SizeOf(s)); // ShortString schreiben BlockWrite(F, d, SizeOf(d)); // Double schreiben finally CloseFile(F); end; AssignFile(F, 'Test.bin'); try FileMode := fmOpenRead; // Lesen Reset(F, 1); // 1 Byte RecordSize BlockRead(F, i, SizeOf(Integer)); // Integer Schreiben BlockRead(F, s, SizeOf(s)); // ShortString schreiben BlockRead(F, d, SizeOf(d)); // Double schreiben finally CloseFile(F); end; WriteLn(i); WriteLn(s); WriteLn(d); end.
Generell lässt sich über die Verschiedenen Dateien sagen, Binärdateien sind deutlich schneller zu lesen, dafür aber nicht mit normalen Editoren veränderbar. Textdateien sind für jeden Nutzer gut Lesbar und Editierbar. Typisierte Binärdateien sind sehr einfach zu verwenden, und solange man nur einzelne Datentypen sichert eine sehr schnelle einfache Möglichkeit, die vor allem kürzer ist als die untypisierte Lösung.
Weitere Dateioperationen
Zum arbeiten mit Dateien gibt es noch mehr Funktionen:
function Eof(FileHandle): Boolean;
Diese Funktion gibt True zurück wenn das FileHandle auf das Ende der Datei zeigt.procedure Seek(FileHandle; Pos);Code: Alles auswählen
While not Eof(F) do begin // Zeilenweise Auslesen und ausgeben ReadLn(F, s); WriteLn(s); end;
Diese Funktion setzt die Position des FileHandle auf Pos. Pos gibt die Position als Einheiten in RecordSize an oder in Größe des Typs bei typisierten Dateien. Seek funktioniert nicht auf Textdateien, sondern nur auf Binären Dateien.function FilePos(FileHandle): Integer;Code: Alles auswählen
Seek(F, 0); Read(F, i); // Erstes Element auslesen Seek(F, 2); Read(F, i); // Drittes Element auslesen
Diese Funktion gibt die aktuelle Position des FileHandles zurück. Wie bei Seek auch wird die Position als Einheiten in Record bzw. Typgrößen angegeben.Code: Alles auswählen
Seek(F, FilePos(F) - 1); Read(F, i); // Vorheriges Element auslesen
Arrays, Strings und Zeiger schreiben
Zuletzt möchte ich noch kurz darauf eingehen wie man Arrays und Strings in Binärdateien schreibt. Bei statischen Arrays und ShortStrings ist das absolut kein Problem, und die können genau so wie andere Variablen auch geschrieben werden. Dynamische Strings und Arrays allerdings sind letztlich Zeiger, und würde man diese einfach so schreiben würde das nur den Zeiger in die Datei schreiben, welcher beim nächsten lesen wahrscheinlich nicht mehr gültig ist, oder vielleicht auf ein Komplett anderes Element zeigt. Dafür sehen wir uns zunächst einmal an wie wir Zeiger schreiben würden:Durch den Dereferenzierungsoperator ^ geben wir an dass wir den Inhalt auf den der Zeiger zeigt schreiben wollen, bzw. das Gelesene das Element hinter dem Zeiger schreiben wollen.Code: Alles auswählen
var PInt1: PInteger; F: File; begin // Initialisierung von F und PInt1 BlockWrite(F, PInt1^, SizeOf(Integer)); //... BlockRead(F, PInt1^, SizeOf(Integer)); end;
Bei Arrays oder Strings können wir es genauso machen, wir können diese einfach in einen Pointer Casten und dann über ^ Schreiben lassen. Da die Länge allerdings Dynamisch ist müssen wir noch dazu speichern wie viele Elemente wir schreiben werden. Außerdem müssen wir bei dem Count Parameter noch die Anzahl an Elementen und ihre Größe berücksichtigen:vor dem Lesen müssen wir dann die Länge auslesen und den Array/String mit SetLength auf diese Länge setzen:Code: Alles auswählen
var arr: Array of Integer; Str: AnsiString; Len: Integer; F: File; begin // Initialisierung // Array schreiben Len := Length(arr); BlockWrite(F, Len, SizeOf(Len)); BlockWrite(F, PInteger(arr)^, Len * SizeOf(Integer)); // String Schreiben Len := Length(Str); BlockWrite(F, Len, SizeOf(Len)); BlockWrite(F, PChar(Str)^, Len * SizeOf(Char)); end;
Eine andere Möglichkeit ist es statt Zeiger zu nehmen Arrayelemente zu Adressieren:Code: Alles auswählen
var Arr: Array of Integer; Str: AnsiString; Len: Integer; begin // Initialisierung // Array Lesen BlockRead(F, Len, SizeOf(Len)); SetLength(arr, Len); BlockRead(F, PInteger(arr)^, Len * SizeOf(Integer)); // String Lesen BlockRead(F, Len, SizeOf(Len)); SetLength(Str, Len); BlockRead(F, PChar(Str)^, Len * SizeOf(Char)); end;
Code: Alles auswählen
var arr: Array of Integer; Str: AnsiString; Len: Integer; F: File; begin // Initialisierung // Array schreiben Len := Length(arr); BlockWrite(F, Len, SizeOf(Len)); BlockWrite(F, arr[0], Len * SizeOf(Integer)); // String Schreiben Len := Length(Str); BlockWrite(F, Len, SizeOf(Len)); BlockWrite(F, Str[1], Len * SizeOf(Char)); // Array Lesen BlockRead(F, Len, SizeOf(Len)); SetLength(arr, Len); BlockRead(F, arr[0], Len * SizeOf(Integer)); // String Lesen BlockRead(F, Len, SizeOf(Len)); SetLength(Str, Len); BlockRead(F, Str[1], Len * SizeOf(Char));
Damit können auch sehr gut nur Teile eines Arrays oder Strings gelesen bzw. geschrieben werden. Allerdings hat das den Nachteil, wenn man mit einem Debugger arbeitet (z.B. dem GDB) welcher mit Array RangeChecks arbeitet kann es vorkommen, dass dieser Dabei Fehler wirft, weil man bei einem Leeren Array kein Element Adressieren sollte (auch wenn in diesem Fall eh kein Zugriff geschehen würde da Len = 0 wäre). Also ein Fehlarlam, welcher dennoch sehr nervig sein kann.
-
- Beiträge: 36
- Registriert: Di 31. Jan 2017, 17:18
Re: Datenspeicherung allgemein
Puh - da hab ich erstmal was zu lesen
Danke für die Aufklärung. Habe es mit begrenzten Strings versucht, also String[40], und es geht.
Danke nochmal.
Bernhard

Danke für die Aufklärung. Habe es mit begrenzten Strings versucht, also String[40], und es geht.
Danke nochmal.
Bernhard
-
- Beiträge: 6918
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Datenspeicherung allgemein
Das hätte ich auch so gemacht, für den Anfang, ist dies die einfachste Lösung.Danke für die Aufklärung. Habe es mit begrenzten Strings versucht, also String[40], und es geht.
Wen es professionell sein soll, dann würde ich TFileStream vorziehen.
Damit kann man Strings, beliebiger Länge und auch dynamische Array speichern.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Datenspeicherung allgemein
Hint: Du solltest Dir überlegen, ob Du wirklich integer abspeichern willst. Die PLZ als String zu speichern benötigt zwar etwas mehr Platz - nee, wenn Dein integer ein 64bit-int ist sogar weniger, aber Deine Dateien sind im Editor lesbar.
Die Write/Read Funktionen für integer, real usw. stammen aus Zeiten, als man mit jedem Byte geizen musste. Das hat aber den Nachteil, dass Deine Dateien schwer lesbar sind, wenn Du sie mit einem anderen Programm öffnest. Heute kostet weder Speicherplatz noch die Wandlung von String zu Int oder Float nennenswert was. Deswegen Werte zu String wandeln und im Klartext abspeichern.
Die Write/Read Funktionen für integer, real usw. stammen aus Zeiten, als man mit jedem Byte geizen musste. Das hat aber den Nachteil, dass Deine Dateien schwer lesbar sind, wenn Du sie mit einem anderen Programm öffnest. Heute kostet weder Speicherplatz noch die Wandlung von String zu Int oder Float nennenswert was. Deswegen Werte zu String wandeln und im Klartext abspeichern.
-
- Beiträge: 36
- Registriert: Di 31. Jan 2017, 17:18
Re: Datenspeicherung allgemein
Nachdem alles sich wunderbar compilieren läßt habe ich nun das Problems eines Laufzeitfehlers. Da die gesuchte Datei noch nicht vorhanden ist kann das Programm sie natürlich nicht finden.Mathias hat geschrieben:Das hätte ich auch so gemacht, für den Anfang, ist dies die einfachste Lösung.Danke für die Aufklärung. Habe es mit begrenzten Strings versucht, also String[40], und es geht.
Wen es professionell sein soll, dann würde ich TFileStream vorziehen.
Damit kann man Strings, beliebiger Länge und auch dynamische Array speichern.
Wie kann ich denn die Datei erstellen?
Habe es mit FileCreate versucht, aber dazu brauche ich ja ein Handel.
Das mit TFileStream würde ich ja machen, aber damit kenn ich mich nun garnicht aus.
(meine Erfahrungen mit Turbo Pascal liegen mehr als 25 Jahre zurück oder so. Da war noch nix mit "Objektorientiert" und/oder "Vererbung" - da war alles Ereignisgesteuert).
In den Büchern wird da auch nix zu gesagt. Der Autor des Lazarus-Buches verweist auf das nächste Buch (Teil 2), aber das ist noch garnicht auf dem Markt.
Zuletzt geändert von BernhardDEL am So 5. Feb 2017, 18:39, insgesamt 1-mal geändert.
-
- Beiträge: 36
- Registriert: Di 31. Jan 2017, 17:18
Re: Datenspeicherung allgemein
Du hast natürlich recht.Timm Thaler hat geschrieben:Hint: Du solltest Dir überlegen, ob Du wirklich integer abspeichern willst. Die PLZ als String zu speichern benötigt zwar etwas mehr Platz - nee, wenn Dein integer ein 64bit-int ist sogar weniger, aber Deine Dateien sind im Editor lesbar.
Bei einer Datei, die nur PLZ und Stadt beinhaltet spielt es keine Rolle, ob die im Editor verändert wird oder nicht.
Problematischer ist es da schon bei personenbezogenen Daten wie z.B. der Fahrer- oder Kundendatei.
Auch die Datei mit den Arbeitsblättern, die ja gegebenenfalls als rechtlicher Nachweis Bestand haben muss, darf nicht so einfach zu manipulieren sein.
Da muss ich mir eh später noch was einfallen lassen, von wegen Verschlüsselung oder so -- aber im Moment ist es wichtiger, dass ich meine Dateien erstellt bekomme, wenn sie noch nicht da sind

-
- Beiträge: 1224
- Registriert: So 20. Mär 2016, 22:14
- OS, Lazarus, FPC: Win7-64bit Laz1.9.0 FPC3.1.1 für Win, RPi, AVR embedded
- CPU-Target: Raspberry Pi 3
Re: Datenspeicherung allgemein
Auch beliebt: Für Hausnummern int zu nehmen, und dann hat da jemand die 3b. Oder ausländische "Postleitzahlen" können durchaus mehr als 5 Stellen haben und Buchstaben enthalten. Oder ein Adressbuch, bei dem man in der Telefonnummer nur Ziffern eingeben kann: +33 als Ländervorwahl?
Schränke Dich im Datenformat so wenig wie möglich ein, erspart Dir hinterher viel Ärger.
Schränke Dich im Datenformat so wenig wie möglich ein, erspart Dir hinterher viel Ärger.
-
- Beiträge: 36
- Registriert: Di 31. Jan 2017, 17:18
Re: Datenspeicherung allgemein
Timm, darum kann ich mich immer noch kümmern.Timm Thaler hat geschrieben:Auch beliebt: Für Hausnummern int zu nehmen, und dann hat da jemand die 3b. Oder ausländische "Postleitzahlen" können durchaus mehr als 5 Stellen haben und Buchstaben enthalten. Oder ein Adressbuch, bei dem man in der Telefonnummer nur Ziffern eingeben kann: +33 als Ländervorwahl?
Schränke Dich im Datenformat so wenig wie möglich ein, erspart Dir hinterher viel Ärger.
Jetzt ist es erst einmal wichtig, dass ich die Datei auch erstellt bekomme.
Die Länderkennung habe ich in meinem Programm eh separat festgehalten. Von daher kein Problem. Da wird dann auch die Ländervorwahl mit gespeichert.
Auch die Telefonnummer ist in Vorwahl und Nummer gesplittet.
Mein Problem liegt im Moment in der Speicherung der Daten in entsprechenden Dateien.

Zur Zeit weis ich auch noch nicht, wie ich meine Daten in die Items der Comboboxen bekomme.

Wie gesagt sind meine Erfahrungen im Bezug auf Programmierung schon sehr alt (ich hinke der Entwicklung hinterher)
und mit 62 Jahren ist man auch nicht mehr so flexibel

Re: Datenspeicherung allgemein
Wenn du das nicht mit TFileStream machen willst/kannst, dan könnte eine mögliche Lösung so aussehen.BernhardDEL hat geschrieben: -- aber im Moment ist es wichtiger, dass ich meine Dateien erstellt bekomme, wenn sie noch nicht da sind
Code: Alles auswählen
var PLZ_Stadt: file of Type_PLZ_Stadt;
// Dateinummer holen
AssignFile(PLZ_Stadt, 'Datei.ext');
// vor dem öffnen die Fehlerbehandlung selbst übernehmen
{$I-}
Reset(PLZ_Stadt);
// Prüfen, ob ein Fehler Aufgetreten ist
If(IOResult <> 0) then // Wenn Fehler, dann
ReWrite(PLZ_Stadt); // Datei erzeugen
{$I+} // Überprüfung wieder zurücksetzen
-
- Beiträge: 2120
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
Re: Datenspeicherung allgemein
Für so etwas hält man sich eigentlich an die nationale Norm. Grade in Deutschland ist das vom Staat explizit geregelt was wie erlaubt ist, und sollte sich da was Ändern so wird das sehr lange Zeit im Voraus angekündigt. Ich glaube sogar der Staat selbst gibt Definitionen für Unternehmen raus welche im Hinblick auf die zu verwendenden Datentypen alles genau definieren (Wie lang eine Hausnummer maximal sein darf, was für Zeichen vorkommen dürfen, etc.) Aber ich denke für den Fragensteller ist das wohl jetzt erst mal das geringste Problem.Timm Thaler hat geschrieben:Auch beliebt: Für Hausnummern int zu nehmen, und dann hat da jemand die 3b. Oder ausländische "Postleitzahlen" können durchaus mehr als 5 Stellen haben und Buchstaben enthalten. Oder ein Adressbuch, bei dem man in der Telefonnummer nur Ziffern eingeben kann: +33 als Ländervorwahl?
Schränke Dich im Datenformat so wenig wie möglich ein, erspart Dir hinterher viel Ärger.
Zu 1. ich zitiere mein eigenes ZitatBernhardDEL hat geschrieben:1. Jetzt ist es erst einmal wichtig, dass ich die Datei auch erstellt bekomme.
2. Zur Zeit weis ich auch noch nicht, wie ich meine Daten in die Items der Comboboxen bekomme.

Zu 2. je nach Dateityp (Text, Typisiert, untypisiert) sind auch bei meinem Tutorial einige Beispiele, z.B. für Untypisierte Dateien zu lesen (also dateien in denen verschiedene Information verschiedener Typen reingeschrieben werden:Mit dem AssignFile wird das Handle zugewiesen, danach muss die Datei allerdings noch geöffnet werden. Das öffnen geschieht über Reset, Rewrite oder Append.
Append ist zum Schreiben am Ende von Textdateien, also zum Anhängen von Texten. Rewrite erstellt eine neue Datei, exsistiert die Datei bereits wird sie überschrieben. Reset öffnet Textdateien zum lesen, oder Binärdateien zum Lesen und/oder Schreiben.
Code: Alles auswählen
AssignFile(F, 'Test.bin');
try
FileMode := fmOpenRead; // Lesen
Reset(F, 1); // 1 Byte RecordSize
BlockRead(F, i, SizeOf(Integer)); // Integer nach Variable i Lesen
BlockRead(F, s, SizeOf(s)); // ShortString nach Variable s Lesen
BlockRead(F, d, SizeOf(d)); // Double nach Variable d Lesen
finally
CloseFile(F);
end;
Und wie du Variablen in deine Comboboxen bekommst solltest du selbst wissen
