Lazarus: Wo ist mein Fehler bei "Blockread"?

Gast #4803130
Lesenswert?
• ▲
▼
Hallo Leute,

als Lazarus-Anfänger hänge ich fest.

procedure TForm1.Button1Click(Sender: TObject);
const C_FNAME = 'ab.log';
var  log_datei: file;
  x : integer ;

begin

    Assignfile(log_datei, C_FNAME);
    Reset(log_datei,1);
    while not Eof(log_datei) do begin

          blockread(log_datei,x,sizeof(x));

    end;

Einfach die Datai ab.log öffnen, aber es kommt immer Run-Error (100)
Wer kann mir da bitte kurz helfen? Vielen Dank
Gast #4803274
Lesenswert?
• ▲
▼
Die Datei existiert, ist 27kb groß. Sie liegt in dem Ordner, in dem das 
Projekt gespeichert wird und auch das Programm hincompeliert wird.

Danke für die Fehlertabelle. Laut meinem bescheidenen Englisch kommt der 
Fehler, wenn ich zu erst das Ende der Datei lesen will, anstatt des 
Anfanges. Aber ich habe nur Quellcode aus dem Internet genutzt, nix 
eigenes erstellt, außer die Variablen umbenannt...
#4803435
Lesenswert?
• ▲
▼
Manfred schrieb:
> wenn ich zu erst das Ende der Datei lesen will
1
procedure CodeBlocks();
2
var F: File;
3
  fsiz, xsiz: longint;
4
  x: integer; //Lesepuffer
5
begin
6
  AssignFile(F, 'ab.log');
7
  Reset(F, 1);
8
  fsiz := FileSize(F);
9
  xsiz := Sizeof(x);
10
  while (fsiz >= xsiz) do begin
11
    fsiz := fsiz - xsiz;
12
    Seek(F, fsiz);
13
    BlockRead(F, x, xsiz);
14
    //... x weiter verarbeiten
15
  end;
16
  CloseFile(F);
17
end;

"while not EOF(F) ..." ist beim Rückwärts-Lesen nicht verwendbar, weil 
ja sofort EOF auftritt, wenn Daten am Dateiende zuerst gelesen werden. 
Ist die Dateigröße kein ganzzahliges Vielfaches der Datenblockgröße, 
dann wird der Datenblock am Dateianfang nicht mehr gelesen. LG
Gast #4803470
Lesenswert?
• ▲
▼
Wie ist die Datei genau aufgebaut?
Gib mal bitte ein paar Beispieldaten.

Und was versuchst du aus der Datei auszulesen?

Wie andere vorher schon geschrieben haben, liest du integer-große Blöcke 
aus der Datei, also jeweils 4 Byte groß.

Jim M. schrieb:
> Hier wäre die genaue Größe in Bytes entscheidend. Wenn die nicht durch
> 4 teilbar ist ergibt sich der 100er Fehler automatisch am Ende.

Manfred schrieb:
> Laut meinem bescheidenen Englisch kommt der
> Fehler, wenn ich zu erst das Ende der Datei lesen will, anstatt des
> Anfanges.
Nein, der Fehler kommt daher, dass du versuchst, hinter dem Ende der 
Datei zu lesen.
Nämlich dann, wenn weniger als 4 Byte bis zum Dateiende zu lesen sind.

Um das zu verhindern, verwende folgendes:
1
procedure BlockRead(
2
  var f: file;
3
  var Buf;
4
  count: Word;
5
  var Result: Integer
6
);

Leg dir eine neue Integer-Variable für Result an und setz diese als 4. 
Parameter für deinen BlockRead-Aufruf ein.
Dadurch erhältst du die Anzahl der gelesenen Bytes, und der Error 100 
verschwindet.

Aber irgendwie schon merkwürdig, dass eine Binäre Datendatei im 
richtigen Format eine falsche Dateigröße hat...

Sieht deine Datei so aus:
1
Ò  .
Im Hex-Editor so:
1
D2 04 00 00 2E 16 00 00
Dann würde dein Code folgendes zurückliefern:
1. Schleifendurchlauf: x=1234
2. Schleifendurchlauf: x=5678

Oder sieht deine Datei eher so aus:
1
1234
2
5678
3
0815
4
4711
Im Hex-Editor so:
1
31 32 33 34 0D 0A 35 36 37 38 0D 0A 30 38 31 35 0D 0A 34 37 31 31
Dann wäre deine Methode völlig ungeeignet, denn dein Code würde 
folgendes zurückliefern:
1. Durchlauf: x=875770417
2. Durchlauf: x=909445645
3. Durchlauf: x=168638519
4. Durchlauf: x=892418096
5. Durchlauf: x=926157325
6. Durchlauf: x=926167345
Und ich kann mir irgendwie nicht vorstellen, dass du das wolltest...
Gast #4803484
Lesenswert?
• ▲
▼
Vielen Dank für die Hilfe. Ich fange dann doch mal von vorne an:
Ich habe eine Datei, binär-Datei, Ascii-Zeichen, die ich auslesen will, 
als in reinster Ur-Form, ohne irgendwelche Schnörkel. Also Byte für 
Byte. Dies soll am besten mit Blockread gehen...stimmt das überhaupt, 
oder gibt es da eine andere Möglichkeit?
Gast #4803508
Lesenswert?
• ▲
▼
Also wenn du byte-weise auslesen willst, muss deine Variable "x" auch 
als Byte deklariert sein, dann bekommst du in jedem Schleifendurchlauf 
auch genau 1 Byte.

Ein Integer ist 4 Byte groß, also liest du mit als Integer definiertem 
"x" 4 Bytes auf einmal, die dann als ein Integer interpretiert werden.

Ändere deine Definition von "x" also zu "Byte" oder "AnsiChar", je 
nachdem was du mit dem Wert machen willst.

BlockRead ist eigentlich dafür gedacht, größere Blöcke auf einmal zu 
lesen, beispielsweise in ein Array.
Du kannst es natürlich trotzdem verwenden, sonderlich performant wird 
das aber nicht.
#4803509
Lesenswert?
• ▲
▼
Georg schrieb:
> zuerst die Datei öffnen und dann ein FileSeek ans Dateiende.

Ohne Reset(F, 1) gibt es hier eine Exeption (exitcode 217). Mit Reset() 
nach Assign() wird die Datei in den Lese-Modus gesetzt. Danach kann mit 
Seek() der Dateizeiger gesetzt werden, Seek(F, 0) ist der Dateianfang, 
Seek(F, FileSize(F)-1) ist das letzte Byte bzw. Zeichen am Dateiende.

Manfred schrieb:
> Byte für Byte

"var x: Byte;" anstatt "var x: integer;", aber nicht "var x: char;", 
weil mit einem untypisierten Dateiobjekt "var f: file" gearbeitet wird.
Gast #4803521
Lesenswert?
• ▲
▼
Ich finde es immer wieder toll, wenn Leute, die nach eigenen Angaben 
Anfänger sind, keine Überprüfungen brauchen...
Man überprüft beim Öffen ob OK.
Man überprüft beim Lesen ob gelesen.
... muss aber nicht sein ...

Ob Reset(log_datei,1); in Ordnung war, kann man Überprüfen.
Ob blockread(log_datei,x,sizeof(x),gelesen); in Ordnung ist kann man...
Die Schreiber der Funktionen/Prozeduren haben es zumindest vorgesehen.
#4803597
Lesenswert?
• ▲
▼
Robert L. schrieb:
> der Fehler ist, Blockread überhaupt zu verwenden.

Er hätte z.B. "var F: file of byte; x: byte;" und dann "read(F, x);" 
anstatt BlockRead() nehmen können. Das ganze Zeugs gab es ja schon in 
TPascal unter DOS. Lazarus habe ich nicht, nehme aber einfach mal an, 
daß sich der TE für einen Umstieg auf TFileStream erstmal eingehend mit 
entsprechenden Klassen und Objekten beschäftigen müßte.
#4803649
Lesenswert?
• ▲
▼
Rainer V. schrieb:
> nehme aber einfach mal an,
> daß sich der TE für einen Umstieg auf TFileStream erstmal eingehend mit
> entsprechenden Klassen und Objekten beschäftigen müßte.

Die drei Methoden von TFileStream zu lernen die er braucht ist auch 
nicht komplizierter als sich mit den drei oder vier verstaubten file 
Funktionen auseinanderzusetzen die er vielleicht braucht, nur daß er um 
ersteres eh nicht herumkommen wird und letzteres heute eigentlich nicht 
mehr verwendet wird.
Gast #4803675
Lesenswert?
• ▲
▼
Hallo Manfred,

bevor du versuchst auf die Datei zuzugreifen solltest du erstmal mal 
prüfen lassen, ob dein Programm die Datei überhaupt finden kann:
1
if not FileExists(C_FNAME) then
2
   begin
3
      readln('Datei ''',C_FNAME,''' nicht gefunden !');
4
      halt(1)
5
   end;
Wie oben bereits erwähnt wurde mußt du die Variable x als Byte 
definieren, da Integer länger als ein Byte ist.

Manfred schrieb:
> Laut meinem bescheidenen Englisch kommt der
> Fehler, wenn ich zu erst das Ende der Datei lesen will, anstatt des
> Anfanges.
Nein, du hast falsch übersetzt. Der Fehler kommt wenn man hinter dem 
Dateiende weiter liest.

Stefan B. schrieb:
> Ein Integer ist 4 Byte groß, also liest du mit als Integer definiertem
> "x" 4 Bytes auf einmal, die dann als ein Integer interpretiert werden.
Das stimmt nicht. Die Länge von Integer ist nicht fest definiert. 
Abhängig vom System kann Integer 2 oder 4 Byte lang sein.
#4803681
Lesenswert?
• ▲
▼
Bernd K. schrieb:
> verstaubten file Funktionen ...
> heute eigentlich nicht mehr verwendet wird.

Ist bei mir auch öfter so, daß der AV-Scanner anschlägt, wenn ich den 
verstaubten Kram in FPC kompiliere (passiert allerdings auch beim 
Kompilieren von C/C++ Konsolenprogrammen unter CodeBlocks mit MinGW).
#4803718
Lesenswert?
• ▲
▼
1
procedure TForm1.Button1Click(Sender: TObject);
2
const
3
  C_FNAME = 'ab.log';
4

5
var
6
  FS: TFileStream;
7
  X: DWord;
8

9
begin
10
  try
11
    FS := TFileStream.Create(C_FNAME, fmOpenRead);
12
    Memo1.Append('file is open for reading');
13

14
    try
15
      while FS.Position + SizeOf(X) <= FS.Size do begin
16
        FS.Read(X, SizeOf(X));
17
        Memo1.Append(Format('Read: %0.8x', [X]));
18
      end;
19
      Memo1.Append('no more data to read');
20

21
    except
22
      Memo1.Append('Error while trying to read from file');
23
    end;
24

25
    Memo1.Append('closing file');
26
    FS.Free;
27

28
  except
29
    Memo1.Append('could not open File');
30
  end;
31
end;
Gast #4804120
Lesenswert?
• ▲
▼
GeraldB schrieb:
> Stefan B. schrieb:
>> Ein Integer ist 4 Byte groß, also liest du mit als Integer definiertem
>> "x" 4 Bytes auf einmal, die dann als ein Integer interpretiert werden.
> Das stimmt nicht. Die Länge von Integer ist nicht fest definiert.
> Abhängig vom System kann Integer 2 oder 4 Byte lang sein.
Ich komme von Delphi, und da ist ein Integer 4 Byte lang. Immer.
Deshalb nahm ich an, dass wäre bei Lazarus/FreePascal genauso, wäre ja 
auch sinnvoll.
Gast #4804227
Lesenswert?
• ▲
▼
Stefan B. schrieb:
> Ich komme von Delphi, und da ist ein Integer 4 Byte lang. Immer.
> Deshalb nahm ich an, dass wäre bei Lazarus/FreePascal genauso, wäre ja
> auch sinnvoll.

In den Handbüchern von FreePascal und Lazarus steht dazu folgendes:
1
The 'integer' type maps to the smallint type in the default Free Pascal mode. It maps to either a
2
longint in either Delphi or ObjFPC mode. The 'cardinal' type is currently always mapped to the
3
longword type.

Die Länge von Integer ist im Standard Pascal nicht festgelegt. Üblich 
sind 2 oder 4 Byte.
Die Länge von Integer ist auch abhängig von der Datenbusbreite der CPU 
und vom Betriebssystem.

Als ich vor 35 Jahren auf dem Apple 2 Pascal (UCSD Pascal und Turbo 
Pascal unter CP/M mit Z80-Karte) gelernt habe, war Integer 2 Byte 
lang. Und laut einem Buch zu Turbo Pascal 6 für PC war Integer auch 
nur 2 Byte lang. Und irgendwann hat dann Borland bei Delphi auf 4 Byte 
umgestellt. Und evtl. kommt ja Embarcadero irgendwann noch auf die Idee 
für 64-bit Programme auf 8 Byte zu verlängern.
Gast #4805041
Lesenswert?
• ▲
▼
Ich habe jetzt etwas probiert und mich für die TFileStream von Bernd K. 
entschieden. Die Daten werden zu je 4 Zeichen pro Zeile als 2 Zeichen 
Hex angezeigt...nur leider von hinten nach vorne, also 4tes 3tes 2tes 
1tes Zeichen. Könnte man das beim Einlesen/Weitergeben an die 
Memokomponente unterbinden? Und kann man das mit TFileStream.Read 
eingelesene nicht gleich in richtiger Reihenfolge einem string 
übergeben, bei Beibehaltung der "Hex-Darstellung"?
Gast #4805048
Lesenswert?
• ▲
▼
Nachtrag: Sämliche Bemühungen scheitern dort, daß die 
inttostr(x)-Funktion wieder aus dem Hex-Code ein normales Ascii-Zeichen 
macht, welches man wieder per Hand mit inttohex (char) konvertieren 
müsste.
Ein Array mit Char anlegen und TFileStream.Read per Pointer zuweisen und 
dann den Index invertieren? Bin da etwas ratlos..
Gast #4805381
Lesenswert?
• ▲
▼
Hallo Manfred,

das Programm von Bernd K. kann auch gar nicht richtig funktionieren, da 
er dort den 4 Byte langen Datentyp Dword verwendet. Vereinfacht 
ausgedrückt: Wenn ein ganzzahliger Datentyp länger als 1 Byte ist, 
werden für x86-Prozessoren die Bytes in umgekehrter Reihenfolge im RAM 
abgelegt. Daher die Drehung der Daten die du festgestellt hast.

Wir stochern hier im dunklen, da du keine Infos zum Aufbau deiner Datei 
nennst und auch nicht sagst wie die Ausgabe der Daten vom Programm 
formatiert sein soll.
#4805473
Lesenswert?
• ▲
▼
GeraldB schrieb:
> das Programm von Bernd K. kann auch gar nicht richtig funktionieren,

Definiere "richtig".

Ich habe mich am Originalbeispiel des OP orientiert das nahelegt er habe 
longint little endian in der Datei.

Außerdem wird nichts in umgekehrter Reihenfolge im RAM angelegt, es wird 
so abgelegt wir es kommt, es wird nur bei der Interpretation als Zahl 
als LE interpretiert. Der OP soll sich mal zu Endianness schlau lesen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren