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
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...
Manfred schrieb:> Die Datei existiert, ist 27kb groß.
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:
> 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
Manfred schrieb:> Laut meinem bescheidenen Englisch kommt der> Fehler, wenn ich zu erst das Ende der Datei lesen will
Soweit ich weiss geht das mit Reset garnicht, man müsste zuerst die
Datei öffnen und dann ein FileSeek ans Dateiende.
Georg
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:
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...
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?
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.
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.
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.
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.
Robert L. schrieb:> der Fehler ist, Blockread überhaupt zu verwenden..>> nimm TFileStream oder ähnliches..
+1
Warum musste es über 13 Postings dauern bis diese naheliegende Antwort
auftauchte?
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.
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.
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).
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.
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.
Stefan B. schrieb:
> Delphi, und da ist ein Integer 4 Byte lang. Immer.
In FPC auch, sofern {$MODE OBJFPC} deklariert ist (hier unter Win7 x64).
Sonst nur 2 Byte, wie bei Smallint, welches den 16-Bit Integer-Typ aus
dem früheren TPascal für DOS ersetzt.
GeraldB schrieb:> Und irgendwann hat dann Borland bei Delphi auf 4 Byte umgestellt.
Dieses "irgendwann" war der Zeitpunkt, als Borland einen 32-Bit-Compiler
'rausbrachte. Das war 1996 mit "Delphi 2".
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"?
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..
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.
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.