"file" type ... Zugriff auf Interna (HANDLE und Konsorten)?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

"file" type ... Zugriff auf Interna (HANDLE und Konsorten)?

Beitrag von Nimral »

Hi allseits,

jeder von uns hat sicher Sequenzen wie

var F: file

Assign(F,....)
Reset(F,...)
Read(F,....)
Close(F,...)

1000 mal verwendet. Jetzt bin ich beim Debuggen eher zufällig auf eine unbeantwortete Frage gestoßen: laut Debugger hat F, oder besser der Typ "file", eine innere Struktur. Da gibt es z.B. HANDLE, MODE, RECSIZE usw. Es scheint aber, dass Code wie

if F.Handle <> 0

nicht durch den Compiler kommt: "illegal qualifier".

Zwei Fragen:

- wieso ist das so, oder habe ich etwas übersehen
- ist es auf Umwegen möglich, "file" seine Geheimnisse abzuluchsen (ich bin besonders scharf auf HANDLE)

Gruss Armin.
Zuletzt geändert von Nimral am Sa 28. Nov 2015, 23:17, insgesamt 1-mal geändert.

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von Nimral »

Bin einen kleinen Schritt weiter. Ich habe die Definition des Typs "File" bzw. "FileRec" gefunden:

http://www.freepascal.org/docs-html/rtl ... lerec.html

FileRec ist also ein packed Record. Handle ist ein THandle, THandle ist ein LongInt. Der Vergleich <> 0, den der Compiler in meinem Code mit "Illegal Qualifier" anmäkelt ist also eigentlich zulässig. Hm.

Die Fehlermeldung "Illegal Qualifier" ist ebenfalls dokumentiert:

http://www.freepascal.org/docs-html/3.0 ... rse62.html

Error: Illegal qualifier
One of the following is happening :
You’re trying to access a field of a variable that is not a record.
You’re indexing a variable that is not an array.
You’re dereferencing a variable that is not a pointer.

Trifft alles m.E. nicht zu. Gut, ich habe als Workaround den packed Record Typen, und kann jetzt vermutlich einen Pointer auf FileRec auf die Adresse von F mappen, dann sollte ich auf die Felder zugreifen können. Aber warum hat mein Code den Compiler nicht passiert?

Wer hat eine Erklärung?

Thx

Armin.

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von Socke »

Der Dateizugriff mit Assign, Reset, Read, Close, etc. wird als Bestandteil der Sprache Pascal gewertet; daher sind die file-Typen für den Entwickler transparant d.h. nicht zugreifbar. Wenn du ein Dateihandle benötigtst, kannst du immer noch die Funktionen FileOpen() nutzen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von mse »

Code: Alles auswählen

 
var
 f1: file of byte;
begin
 assignfile(f1,'test.txt');
 writeln(tfilerec(f1).handle,' ',tfilerec(f1).handle = unusedhandle);
 reset(f1);
 writeln(tfilerec(f1).handle,' ',tfilerec(f1).handle = unusedhandle);
 closefile(f1);
 writeln(tfilerec(f1).handle,' ',tfilerec(f1).handle = unusedhandle);
end;
 

Bringt auf Linux z.B.:

Code: Alles auswählen

 
-1 TRUE
8 FALSE
8 FALSE
 

Wenn man "handle" benutzt ist die Chance gross, dass man die internen "file" Funktionen stört.
Was möchtest du konkret erreichen?

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von Nimral »

Dank euch für die hilfreichen Antworten. Ich finde es sowohl unnötig als auch inkonsequent, die Innereien des Filerec vor dem Entwickler zu verbergen. Aber gut.

Ich habs inzwischen auch gelöst, etwas komplizierter: einen Pointer pF = ^FileRec definiert, und ihn mit pF := @F auf mein File Handle gemappt, danach kann ich die pF^.Handle lesen, prima.

Was ich erreichen wollte: Ich habe öfters Konstrukte wie diese:

Code: Alles auswählen

Try
   ... haufenweise code, auch mal dynamisch Speicher reservieren ...
   GetMem oder New ...
   Assign(F,....)
   Rewrite(F,..)
   For ... to
      Blockwrite(F,...)
   Close(F);
   ... haufenweise weiterer code
Finally
   ... der solls richten wenn etwas schief geht
   Close(F)
   Freemem oder Dispose ...


Innerhalb des Try Blocks kann alles mögliche schief gehen, und wenn ich anfange, jeden einzelne Codesequenz mit eigenen try ... except und try ... finally Blöcken abzusichern entsteht ein fürchterliches Dickicht. Mache ich es nicht, komme ich immer wieder in Teufels Küche: verwaiste File Handles blockieren Dateien, und es gibt Speicherlecks. Das Problem ist, dass der Freemem Block nicht erkennen kann, wo die Exception ausgelöst wurde. Handles (um bei denen zu bleiben) können beim Aufräumen also offen sein oder auch nicht, je nachdem wie weit der Code gekommen ist. Manches macht Pascal von selber zu, wenn das Ende der Routine erreicht wurde, aber erstens kann man sich nicht drauf verlassen, und zweitens fand ich bisher keine vollständige Dokumentation dazu, was genau automatisch wann freigegeben wird. Das gilt für Handles ebenso wie für dynamischen Speicher oder das Zerstören von Objekten. Ich möchte auch den Lesern meines Codes, die nach mir kommen, nicht zumuten, dass sie wissen müssen, was Pascal automatisch aufräumt und was nicht, um meinen Code zu verstehen. Das gilt auch und gerade bei Objekten: manche räumen sich sauber wieder ab, wenn die Routine beendet wurden, und bei manchen muss man selber irgendeine Free oder Destroy Routinen aufrufen. Hinweise dazu in den Dokus finden sich überaus spärlich.

Daher bin ich dazu übergegangen, im Finally konsequent alles zu zu machen oder freizugeben, was ich davor irgendwo aufgemacht habe, selbst wenn ich dazu ein paar Zeilen unnützen Code mehr schreiben muss. Dazu muss ich z.B. nachsehen, ob ein Handle auch geöffnet wurde, weil sonst der finally Code seinerseits wieder in Exceptions läuft.

also:

Code: Alles auswählen

 
finally
   if pF^.Handle > 0 then close(F);   // Datei ist noch offen
   if pBuffer <> NIL then FreeMem(pBuffer,READ_BUFFER_SIZE)     // Speicher wurde reserviert


Speicherzeiger gebe ich im finally Block frei, wenn sie nicht mehr NIL sind. Handles sind noch offen wenn sie >0 sind. Bisher bin ich mit dieser Methodik ganz gut gefahren.

Und natürlich würde mir nicht im Traum einfallem, die Handles oder Adressen beschreiben zu wollen, ich muss sie nur lesen, um zu sehen ob sie verwendet wurden, und das sollte kein Problem sein :-).

Armin.

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von Nimral »

Socke hat geschrieben:Der Dateizugriff mit Assign, Reset, Read, Close, etc. wird als Bestandteil der Sprache Pascal gewertet; daher sind die file-Typen für den Entwickler transparant d.h. nicht zugreifbar. Wenn du ein Dateihandle benötigtst, kannst du immer noch die Funktionen FileOpen() nutzen.


Thx, das ist nützlich, macht meinen Code noch einfacher. Ich hatte irgendwie nicht mitbekommen, dass die guten alten Open und Close Befehle irgendwann auch Handle basierte Zwillinge bekommen haben. Wenn ich auf die umsteige, habe ich immer ein Handle zur Verfügung. Ich denke, so mache ich es in Zukunft.

Thx,

Armin.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von mse »

Nimral hat geschrieben:Speicherzeiger gebe ich im finally Block frei, wenn sie nicht mehr NIL sind. Handles sind noch offen wenn sie >0 sind.

Das stimmt leider nicht, siehe mein Beispiel. tfilerec(f1).handle ist nach close() immer noch 8.

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von Nimral »

mse hat geschrieben:
Nimral hat geschrieben:Speicherzeiger gebe ich im finally Block frei, wenn sie nicht mehr NIL sind. Handles sind noch offen wenn sie >0 sind.

Das stimmt leider nicht, siehe mein Beispiel. tfilerec(f1).handle ist nach close() immer noch 8.


Dann muss man eben nachhelfen:

Code: Alles auswählen

close(f1);
f1 := 0;   // wenn der Code hier her kommt, ist der close ohne Exception gelaufen


Immer noch besser, als für jedes dynamisch allokierte Speicherblöcklein oder jedes offene Handle ein eigenes Flag mitzuziehen, oder x Try/Except/Finally Konstrukte zu verschachteln.

Armin.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von mse »

0 ist auf Linux ein gültiges Filehandle (StdIn).

Nimral
Beiträge: 390
Registriert: Mi 10. Jun 2015, 11:33

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von Nimral »

mse hat geschrieben:0 ist auf Linux ein gültiges Filehandle (StdIn).


Guter Hinweis, aber für mich ohne Relevanz.

Gegenfrage: wie machst Du das Error Handling?

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: "file" type ... Zugriff auf Interna (HANDLE und Konsorte

Beitrag von mse »

Ich kann mich nicht mehr erinnern, wann ich das letzte mal assignfile(), reset() und Konsorten verwendet hätte.
Ansonsten wie du, Objekt-Instanzen mit "nil" initialisieren und mit free() abräumen. Filehandle sind meistens in TStream gekapselt und müssen nicht gesondert behandelt werden.

Antworten