Autor Beitrag
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Sa 01.12.12 22:43 
Liebe Experten,

ich habe mit inhaltlich gleich aufgebauten Dateien zu tun, die sich aber in der Formatierung geringfügig unterscheiden, z.B. Punkt statt Komma als Dezimalzeichen. Da kommen auch noch Exoten hinzu. Deshalb soll das eigentliche Programm alles aus einem FilesStream lesen, der die Daten in einem einheitlichen Format enthält. Mit dem Laden oder Lesen kann ich dann alle Umformatierungen machen, ohne dass das eigentliche Programm angefasst werden muss.

Ich habe also TMyFilestream = CLASS(TFilestream) definiert und nehme in CREATE und READ die erforderlichen Umformatierung vor. Läuft seit 2009 gut.

Jetzt habe ich eine Datei, die am Ende eine Anzahl von Textzeilen enthält, jeweils mit #0D#0A abgeschlossen. Das ist genau das Format, wie TStringList.savetostream seinen Inhalt speichert und lädt. Und der Text wäre in einer Stringlist auch bestens zu bearbeiten. Leider führt Stringlist.loadfromstream zu einer AccessViolation. Klar, ich finde schnell einen Work-around, aber loadfromstream gibt es ja für viele Klassen, da wäre mir eine suabere Lösung schon lieb.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
FUNCTION tmyfilestream.Read(VAR Buffer; Count: longint): longint;
TYPE
  t_byte_array = ARRAY[0..2000000000 - 4OF byte;
VAR
  i: integer;
BEGIN
  IF count = 0 THEN {Aufruf aus TStringList }
    BEGIN
      FOR i := 0 TO 20 DO
        t_byte_array(Buffer)[i] := ord('A') + i; { <<<< Hier passiert die AccessViolation }
      t_byte_array(Buffer)[21] := 13{ CR }
      t_byte_array(Buffer)[22] := 10{ LF }
    END
  ELSE { Aufruf aus eigenem Programm } { <<<< Dies geht }
    FOR i := 0 TO count - 1 DO
      t_byte_array(Buffer)[i] := i;
END;
[/code]


Offensichtlich nutzt die TStrinList-Routine einen Speicher, auf den mein Programm nicht zugreifen darf.

Count = 0 scheint übrigens "bis Ende der Datei" zu bedeuten.

Hat jemand Hinweise?

Gruß GuaAck
mandras
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 432
Erhaltene Danke: 107

Win 10
Delphi 6 Prof, Delphi 10.4 Prof
BeitragVerfasst: So 02.12.12 12:15 
Ich habe Deinen Code angewendet (mit Delphi6), der beschriebe Fehler trat nur auf, wenn die zu lesende Datei leer ist.

user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:

Offensichtlich nutzt die TStrinList-Routine einen Speicher, auf den mein Programm nicht zugreifen darf.
Count = 0 scheint übrigens "bis Ende der Datei" zu bedeuten.


Meines Wissens nach nicht.
StringList benutzt TStrings.LoadFromStream und arbeitet beim Einlesen eines Textes wie folgt:
1. Anzahl Bytes bis Streamende ermitteln (über Stream.Size und Stream.Position)
2. Speicherbereich dieser Größe belegen
3. Read des darunterliegenden Streams mit Count= (aus 1.) aufrufen

Das wird der Knackpunkt sein _vermute_ ich:
Wenn die Datei leer ist, wird ein Speicherbereich der Größe 0 angefordert, und Deine Read-Funktion will dort etwas schreiben. Daher die AV.

Für diesen Beitrag haben gedankt: GuaAck
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: So 02.12.12 18:37 
Danke Mandras,

so wird es sein, aus stream.size und stream.position ergibt sich tatsächlich count=0. Ich muss die property position in meiner geerbten Klasse neu schreiben, denn aus dem TFilestream habe ich Daten schon in einen interen Puffer (zur Ünbersetzung) geholt, die TFilestream.position ist deshalb schon weiter als der Lesevorgang aus meiner eigenen Klasse.

Gruß
GuaAck
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Mo 03.12.12 21:25 
NACHTRAG

Hallo Mandras,

Dein Tipp war gut, ich habe position und size in meiner von TFilestream abgeleiteten Klasse neu gemacht. Bei size erfolgt auch der Aufruf meiner Routine von TStringlist.loadfromstream aus, nicht jedoch bei position. Ich habe mir dann im CPU-Fenster den Assembler-Code angesehen: Tatsächlich wird in TStrings.loadfromstream für size ein call auf den übergebenen Stream ausgeführt, bei position wird aber fest verdrahtet TStream.position aufgerufen.

Im Prinzip ein Bug, der nur in diesem Sonderfall auffällt, meistens ist wohl der ganze stream ein komplettes Abbild der TStringlist.

Danke nochmals für die Anregung,

Gruß GuaAck
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Mo 03.12.12 21:47 
user profile iconGuaAck hat folgendes geschrieben Zum zitierten Posting springen:
Im Prinzip ein Bug, der nur in diesem Sonderfall auffällt, meistens ist wohl der ganze stream ein komplettes Abbild der TStringlist.
Stimmt, GetPosition ist nicht die virtuelle Methode, das davon aufgerufene Seek ist es :idea:

Da Seek immer die aktuelle Position nach seiner Aktion zurückgibt, wird da Result := Seek(0, soCurrent); verwendet. So, wie das übrigens auch in GetSize gemacht wird - weiß der Himmel, warum das dann virtuell ist.

Hach ist das alles kaputt. Wurde in XE zwar mal aufgeräumt, aber wirklich logisch ist das immer noch nicht. Dieses ganze Streaming-Zeug ist wie die "Datenzugriffskomponenten" alles Write-Once-Code. Der, der das damals bei Borland geschrieben hat versteht es, und sonst keiner. :?

Jedenfalls: möchtest du die Positionierung ändern, musst du an Seek() ran.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."

Für diesen Beitrag haben gedankt: GuaAck
GuaAck Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 378
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Di 04.12.12 20:18 
Danke Martok,

jetzt habe ich ein eigenes seek in meiner abgeleiteten Klasse gemacht und es geht!

Gruß GuaAck