Delphi und untypisierte Dateien

Ich hab ein kleines Problem. Ich kann zwar ohne Probleme untypisierte Datein schreiben (mit Hexeditor überprüft; die Werte sind Richtig). Aber ich hab Probleme beim auslesen. Es kommt immer ein Fehler. Ach ja, die Prozedur heißt blockread. Wer kann helfen, sollte sich melden!

Ich hab ein kleines Problem. Ich kann zwar ohne Probleme
untypisierte Datein schreiben (mit Hexeditor überprüft; die
Werte sind Richtig). Aber ich hab Probleme beim auslesen. Es
kommt immer ein Fehler. Ach ja, die Prozedur heißt blockread.
Wer kann helfen, sollte sich melden!

Ein typischer Fehler ist das die Blockgröße nicht beachtet wird. Versuch mal ob dein Code mit

Reset(f,1)

beim einlesen funktioniert.

Oder Poste mal einen kleinen Codeausschnitt als Demo.

Gruss,
Matthias Thoma

Ein typischer Fehler ist das die Blockgröße nicht beachtet
wird. Versuch mal ob dein Code mit

Reset(f,1)

beim einlesen funktioniert.

Oder Poste mal einen kleinen Codeausschnitt als Demo.

Gruss,
Matthias Thoma

Hab ich auch schon probiert, aber dann kommt der Fehler „read beyond end of file“. Hier eine Kurze Demo:

procedure laden;
var f:file;
begin
assignfile(f,…);
reset(f);
blockread(f,record,length(record);
laden2(f);
closefile(f);
end;

procedure laden2(var f:file);
begin
while not(eof(f)) do blockread(f,record,length(record);
end;

Mehrere Dinge:

Leider hast Du nicht dazugeschrieben was Record ist. Wahrscheinlich mußt du length durch SizeOf ersetzten.

Wenn du reset ohne explizite angabe der Blockgröße benutzt wird ein Wert von 128 angenommen. D. h.

blockread(f,record,length(record))
liest length(record) * 128 Bytes ein. Das ist dann weit mehr
record gruß ist deshalb der Fehler hier.

while not(eof(f)) do
blockread(f,xrecord,length(record));

Bei laden2 ist der Fehler durch die Dateigröße bestimmt. Nehmen wir an deine Datei hat eine Größe von 520 Byte und length(record) ist 100 Byte.
Dann würde die Schleife 5 mal durchlaufen und 500 Byte sind eingelesen. Beim 6’ten durchgang will Blockread nochmal 100 Byte einlesen, was nicht geht da nur 20 Byte noch da sind. Diese werden eingelesen und eine exception ausgeworfen die du
nur Abfangen mußt. Eine weitere Lösung ist den AmtTransferred hinzuzufügen.

var
t : integer;

while not(eof(f)) do
blockread(f,xrecord,length(record),t); // AmtTransferd hinzugefügt.

Dein Programm wird nun höchstwahrscheinlich laufen.

Gruss,
Matthias Thoma

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hab ich auch schon probiert, aber dann kommt der Fehler „read
beyond end of file“. Hier eine Kurze Demo:

procedure laden;
var f:file;
begin
assignfile(f,…);
reset(f);
blockread(f,record,length(record);
laden2(f);
closefile(f);
end;

procedure laden2(var f:file);
begin
while not(eof(f)) do blockread(f,record,length(record);
end;

Mehrere Dinge:

Leider hast Du nicht dazugeschrieben was Record ist.
Wahrscheinlich mußt du length durch SizeOf ersetzten.

Wenn du reset ohne explizite angabe der Blockgröße benutzt
wird ein Wert von 128 angenommen. D. h.

blockread(f,record,length(record))
liest length(record) * 128 Bytes ein. Das ist dann weit mehr
record gruß ist deshalb der Fehler hier.

while not(eof(f)) do
blockread(f,xrecord,length(record));

Bei laden2 ist der Fehler durch die Dateigröße bestimmt.
Nehmen wir an deine Datei hat eine Größe von 520 Byte und
length(record) ist 100 Byte.
Dann würde die Schleife 5 mal durchlaufen und 500 Byte sind
eingelesen. Beim 6’ten durchgang will Blockread nochmal 100
Byte einlesen, was nicht geht da nur 20 Byte noch da sind.
Diese werden eingelesen und eine exception ausgeworfen die du
nur Abfangen mußt. Eine weitere Lösung ist den AmtTransferred
hinzuzufügen.

var
t : integer;

while not(eof(f)) do
blockread(f,xrecord,length(record),t); // AmtTransferd
hinzugefügt.

Dein Programm wird nun höchstwahrscheinlich laufen.

Gruss,
Matthias Thoma

Tschuldigung ich meinte sizeof(record), war verwirrt, zu wenig schlaf.

Zu Laden2, es wird kein Problem damit geben, weil ich die Datei selbst schreibe und die gleichen Records benutze, so dass eof genügt.
Und zu Record: Record ist ein Record, wenn du nicht weiß was ein Record ist, dann kannst du mir wahrscheinlich nicht weiterhelfen. Selbst wenn du teile aus der Hilfe zitierst (da hab ich als ertses geguckt!).

Gruss Thomas

Zu Laden2, es wird kein Problem damit geben, weil ich die
Datei selbst schreibe und die gleichen Records benutze, so
dass eof genügt.

Und zu Record: Record ist ein Record, wenn du nicht weiß was
ein Record ist, dann kannst du mir wahrscheinlich nicht
weiterhelfen.

Das ist ein record:
type
xyz = record
HalloWelt : string;
end;

So und jetzt sag mir wie groß string jeweils ist. Könnte ein Fehler (ist sogar ein sehr typischer) sein.

Das ist auch ein record:
type
xyz = record
case Integer of
0: (
a: integer;
b: integer);
1: (
c: string[80]);
end;
end;

Irgendwas = record
Bereiche: 1…12;
end;

Du könntest auch noch irgendwelche Klassen innerhalb des Records haben:

Irgendwas = record
a: TStrings;
end;

dann gibts die geschichten noch packed und unpacked und man kann die obigen noch kombinieren etc.

Ich hoffe ich konnte deutlich machen das es Wichtigkeit ist wie der Record definiert ist und wie er dann verwendet wird.

Gruss,
Matthias Thoma

Das ist ein record:
type
xyz = record
HalloWelt : string;
end;

So und jetzt sag mir wie groß string jeweils ist. Könnte ein
Fehler (ist sogar ein sehr typischer) sein.

In diesem Fall kann der String max 255 Zeichen haben, in unserer Welt reicht für jedes Zeichen ein Byte(8Bit)(anders in Japan/China/usw., da sind es 2 Byte, wegen der grossen Menge von Zeichen). Außerdem beschreibt das erste Byte die länge des Strings. Also insgesamt 256, was glecih 2^8 ist.
Folglich, dieses Record beansprucht 256Byte.

Das ist auch ein record:
type
xyz = record
case Integer of
0: (
a: integer;
b: integer);
1: (
c: string[80]); {Hier string sein 81}
end;
end;

Unter win3.X braucht dieses Record 85 Byte. Allerdings unter Win9x 89Byte, weil es im 32Bit Modus arbeitet.

Irgendwas = record
Bereiche: 1…12;
end;

Hier 2Byte.

Du könntest auch noch irgendwelche Klassen innerhalb des
Records haben:

Irgendwas = record
a: TStrings;
end;

2 Byte, ein einfacher Pointer.

dann gibts die geschichten noch packed und unpacked und man
kann die obigen noch kombinieren etc.

Ich hoffe ich konnte deutlich machen das es Wichtigkeit ist
wie der Record definiert ist und wie er dann verwendet wird.

Gruss,
Matthias Thoma

Danke für die Hilfe beim erklären der Records. Mein Records ist vom Typ 1. Das einfachste und das was ich brauchte.

Danke für die Hilfe beim erklären der Records. Mein Records
ist vom Typ 1. Das einfachste und das was ich brauchte.

Wer blöd fragt kriegt eine blöde Antwort oder so… Da du mich als Onlinehilfeabschreiber bezeichnet hast mußt ich halt mal was zeigen :wink:

Das ist ein record:
type
xyz = record
HalloWelt : string;
end;

So und jetzt sag mir wie groß string jeweils ist. Könnte ein
Fehler (ist sogar ein sehr typischer) sein.

In diesem Fall kann der String max 255 Zeichen haben, in : unserer Welt reicht für jedes Zeichen
ein Byte(8Bit)(anders in Japan/China/usw., da sind es 2 Byte, : wegen der grossen Menge von
Zeichen). Außerdem beschreibt das erste Byte die länge des : Strings. Also insgesamt 256, was
glecih 2^8 ist.
Folglich, dieses Record beansprucht 256Byte.

Ach ja, du hast nicht gesagt welche Delphi Version du verwendest. Ansonsten sind es nämlich NICHT 256 Byte
groß. Ach ja. Was heißt eigentlich „in unserer Welt“ gibts denn noch eine?

Um deine Ausführungen zu ergänzen:
Bevor IBM den erweiterten ASCII Code eingeführt hat haben sogar 7 Bit gereicht. Und wenn manns genau nimmt würden sogar sechs Bit Reichen 2^6 = 64 , das reicht für buchstaben und Satzzeichen.
Der wichtigste zwei Byte Zeichensatz hat sogar einen Namen: UniCode; den wirds demnächst auch verstärkt bei uns geben.
Die ersten 256 Zeichen des Unicodes wiederum entsprechen dem ANSI Zeichensatz (den aus unserer Welt). Ach ja die Zeichen
sind nicht 1 bis 256 sondern 0 bis 255.

Ich glaube wie haben abgeklärt das wir keine Anfänger sind. [Es sei denn du hast die record größen über ShowMessage(strtoint(sizeof(record))) gemacht. Das wäre nämlich Betrug.

Schönen Sonntag noch,

Matthias Thoma

Danke für die Hilfe beim erklären der Records. Mein Records
ist vom Typ 1. Das einfachste und das was ich brauchte.

War ironsich gemeint, aber da es weiter hilft, schweige ich zu deisem Thema.

Wer blöd fragt kriegt eine blöde Antwort oder so… Da du mich
als Onlinehilfeabschreiber bezeichnet hast mußt ich halt mal
was zeigen :wink:

Das ist ein record:
type
xyz = record
HalloWelt : string;
end;

So und jetzt sag mir wie groß string jeweils ist. Könnte ein
Fehler (ist sogar ein sehr typischer) sein.

In diesem Fall kann der String max 255 Zeichen haben, in : unserer Welt reicht für jedes Zeichen
ein Byte(8Bit)(anders in Japan/China/usw., da sind es 2 Byte, : wegen der grossen Menge von
Zeichen). Außerdem beschreibt das erste Byte die länge des : Strings. Also insgesamt 256, was
glecih 2^8 ist.
Folglich, dieses Record beansprucht 256Byte.

Ach ja, du hast nicht gesagt welche Delphi Version du
verwendest. Ansonsten sind es nämlich NICHT 256 Byte
groß. Ach ja. Was heißt eigentlich „in unserer Welt“ gibts
denn noch eine?

Um deine Ausführungen zu ergänzen:
Bevor IBM den erweiterten ASCII Code eingeführt hat haben
sogar 7 Bit gereicht. Und wenn manns genau nimmt würden sogar
sechs Bit Reichen 2^6 = 64 , das reicht für buchstaben und
Satzzeichen.
Der wichtigste zwei Byte Zeichensatz hat sogar einen Namen:
UniCode; den wirds demnächst auch verstärkt bei uns geben.
Die ersten 256 Zeichen des Unicodes wiederum entsprechen dem
ANSI Zeichensatz (den aus unserer Welt). Ach ja die Zeichen
sind nicht 1 bis 256 sondern 0 bis 255.

Ich glaube wie haben abgeklärt das wir keine Anfänger sind.
[Es sei denn du hast die record größen über
ShowMessage(strtoint(sizeof(record))) gemacht. Das wäre
nämlich Betrug.

So was würde mir nie einfallen, außerdem dauert es mir zu lange. Einfach die Rübe benutzt.

Mit unsere Welt meine ich den Westen, die das hier gebräuchliche 26 Buchstaben Alphabet benutzen. Schon ein Land weiter im Osten (Polen) gibt es ein anderes Alphabet und von den Russkies will ich gar nicht anfangen.(Die Japaner haben ca. 20.000 Zeichen, deswegen auch die 2 Byte pro Zeichen)

Ich benutze Delphi 2.0 (lustig oder?!?) oder 1.6, was dier lieber ist.

Schönen Sonntag wünsch ich auch,

Thomas

Danke für die Hilfe beim erklären der Records. Mein Records
ist vom Typ 1. Das einfachste und das was ich brauchte.

War ironsich gemeint, aber da es weiter hilft, schweige ich zu
deisem Thema.

War nicht böse gemeint.

Ich benutze Delphi 2.0 (lustig oder?!?) oder 1.6, was dier
lieber ist.

Opps, jetzt lässt mich mein Gedächtniss im Stich und ich hab grad keine Lust meine D2 CD zu suchen.

Mach mal:
type
z = record
x : string;
end;

und schau nach ob der SizeOf wirklich 256 und nicht 4 ist.

Gruss,
Matthias Thoma

Das ist ein record:
type
xyz = record
HalloWelt : string;
end;

So und jetzt sag mir wie groß string jeweils ist. Könnte ein
Fehler (ist sogar ein sehr typischer) sein.

In diesem Fall kann der String max 255 Zeichen haben, in
unserer Welt reicht für jedes Zeichen ein Byte(8Bit)(anders in
Japan/China/usw., da sind es 2 Byte, wegen der grossen Menge
von Zeichen). Außerdem beschreibt das erste Byte die länge des
Strings. Also insgesamt 256, was glecih 2^8 ist.
Folglich, dieses Record beansprucht 256Byte.

Hi Thomas,

ist Dir der Unterschied zwischen Delphis Datentypen „STRING“ und „SHORTSTRING“ klar?

Mit freundlichem Gruß
Martin

Mach mal:
type
z = record
x : string;
end;

und schau nach ob der SizeOf wirklich 256 und nicht 4 ist.

Gruss,
Matthias Thoma

Es ergibt 4, aber ich muß dich enttäuschen, ich beschränke die Strings auf 5 (variabel:string[50])

Hi Thomas,

ist Dir der Unterschied zwischen Delphis Datentypen „STRING“
und „SHORTSTRING“ klar?

Mit freundlichem Gruß
Martin

Shotstring, Shortstring, ähhh

Sagt mir irgendwie gar nichts.

MfG Ich mal wieder

Hi Thomas,

dann solltest Du die Online-Hilfe konsultieren, um Dein Know-How in diesem Punkt zu erweitern. Ich schätze, Dein Problem mit den Records kommt daher, daß Du den Typ STRING statt SHORTSTRING verwendest. Variablen vom Typ STRINGs sind KEINE „Speicherbereiche von max 256 Bytes Länge, wobei das erste Byte die Länge angibt“ (und deren Länge auch a la s[0] := Chr(9) gesetzt werden kann). Um eine diesem Modell entsprechende Variable zu erhalten, mußt Du sie als SHORTSTRING deklarieren. Delphis STRING-Variablen sind dagegen dynamisch verwaltete, referenzgezählte Objekte, die auch länger als 255 Zeichen sein können (Länge von Haus aus variabel und nicht mehr a la „s[0] := Chr(9)“, sondern nur über Funktion SetLength zu verändern).

Mit freundlichem Gruß
Martin

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Es ergibt 4,

Dann war deine Analyse vorhin aber falsch…

aber ich muß dich enttäuschen, ich beschränke die
Strings auf 5 (variabel:string[50])

Ich hab dein Beispiel von vorhin ausprobiert und bei mir hats geklappt. Ich habs erweitert so das Du siehst wie es funktionieren könnte:

type
 yrecord = record
 rrdd : string[80];
 end;

var
 xrecord : yrecord;

procedure laden2(var f:file);
begin
 while not(eof(f)) do
 begin
 blockread(f,xrecord,SizeOf(XRecord));
 ShowMessage(xrecord.rrdd);
 end;
end;

procedure laden;
var
 f:file;
begin
 assignfile(f,'C:\test.bin');
 reset(f,1);
 blockread(f,xrecord,SizeOf(Xrecord));
 ShowMessage(xrecord.rrdd);
 laden2(f);
 closefile(f);
end;

procedure Speichern;
var
 f:file;

begin
 assignfile(f,'C:\test.bin');
 rewrite(f,1);
 xrecord.rrdd := 'Hallo';
 blockwrite(f,xrecord,SizeOf(Xrecord));
 xrecord.rrdd := 'Welt';
 blockwrite(f,xrecord,SizeOf(Xrecord));
 closefile(f);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
 Speichern;
 Laden;
end;

Gruss,
Matthias Thoma

Shotstring, Shortstring, ähhh

Sagt mir irgendwie gar nichts.

MfG Ich mal wieder

ShortString ist das was bei Delphi 1 und TP der String. Konnte maximal 255 Zeichen haben. War insgesammt 256 Zeichen lang. StringName[0] enthielt die Stringlänge.

Ab Delphi 2 wurde das geändert. Die Strings sind jetzt unbegränzt lang (LONGSTRIGNS), die Länge ist in den 4 Bytes vor dem String kodiert.

Gruss,
Matthias Thoma

type
yrecord = record
rrdd : string[80];
end;

var
xrecord : yrecord;

procedure laden2(var f:file);
begin
while not(eof(f)) do
begin
blockread(f,xrecord,SizeOf(XRecord));
ShowMessage(xrecord.rrdd);
end;
end;

procedure laden;
var
f:file;
begin
assignfile(f,‚C:\test.bin‘);
reset(f,1);
blockread(f,xrecord,SizeOf(Xrecord));
ShowMessage(xrecord.rrdd);
laden2(f);
closefile(f);
end;

procedure Speichern;
var
f:file;

begin
assignfile(f,‚C:\test.bin‘);
rewrite(f,1);
xrecord.rrdd := ‚Hallo‘;
blockwrite(f,xrecord,SizeOf(Xrecord));
xrecord.rrdd := ‚Welt‘;
blockwrite(f,xrecord,SizeOf(Xrecord));
closefile(f);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Speichern;
Laden;
end;

Gruss,
Matthias Thoma

Danke für die Hilfe

Thomas