Records aus einem Byte Array herauslesen?

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut

Records aus einem Byte Array herauslesen?

Beitragvon Helios » 14. Jan 2018, 14:48 Records aus einem Byte Array herauslesen?

Hallo Forenmitglieder,
nach langer Suche im web/Google ohne konkrete Lösung bitte ich hier im Forum um einen Tipp.
Ich suche für folgendes Problem eine elegante Lösung.

Aus einer Datei lese ich via Blockread Byte Arrays heraus, die ich erst zur Laufzeit konktet interpretieren kann

Zum Beispiel kann es sich um ein Array Of TableFuncParam handeln:

Type
TableFuncParam = packed record
Value1: double;
ByteArray: array [0..31] of byte;
end;

Wie gesagt, aus der Datei hole ich mir immer ein Array Of Bytes.

var
TFPArray: Array Of TableFuncParam;
ByteArray: Array Of Bytes;

Nun möchte ich den Byte Array Speicherbereich mit meinem Record Array "zur Deckung" bringen, z.B. mit so einem Konstrukt:
...
TableFuncParam[0] := TableFuncParam(ByteArray[0]);
...

Gibt es eine Lösung mit einem Casting (packed Rekord Array "passt exakt" in das Byte Array)
oder muss ich wirklich Byte-weise die Information vom Byte Array in ein entsptechend neues
TableFuncParam Array kopieren.
Ich hatte auch schon Beispiele mit "absolute" gefunden, bekomme es aber mit Record Arrays nicht zum fliegen.

Im Voraus besten Dank für Eure Rückmeldungen.

Gruß

Arne
Helios
 
Beiträge: 12
Registriert: 29. Jun 2011, 21:36
Wohnort: Leonberg
OS, Lazarus, FPC: Lazarus 1.8.2 Windows 7 64Bit / Lazarus 1.8.0 Debian 9 „Stretch" 64Bit | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 14. Jan 2018, 15:57 Re: Records aus einem Byte Array herauslesen?

Vielleicht hilft dir "absolute" weiter.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4109
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Helios » 14. Jan 2018, 17:13 Re: Records aus einem Byte Array herauslesen?

Hallo Matthias,

wie beschrieben, "absolute" hatte ich schon versucht, aber leider fehlt mir hier ein "griffiges" Beispiel für Arrays Of Records.

Wenn Du diesbzgl. etwas (einen Link oder ein gutes Beispiel) hast, wäre ich Dir sehr dankbar.

Gruß

Arne
Helios
 
Beiträge: 12
Registriert: 29. Jun 2011, 21:36
Wohnort: Leonberg
OS, Lazarus, FPC: Lazarus 1.8.2 Windows 7 64Bit / Lazarus 1.8.0 Debian 9 „Stretch" 64Bit | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 14. Jan 2018, 17:51 Re: Records aus einem Byte Array herauslesen?

Wieso liest du deine Datei nicht mit TStream ein ?
Die Daten von einem Stream kannst du sehr einfach in deinen Record schreiben.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4109
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 14. Jan 2018, 17:58 Re: Records aus einem Byte Array herauslesen?

Ich verstehe zwar nicht, warum du nicht gleich in eine Variable des richtigen Typs (TableFuncParam) einliest, aber das wird schon seinen Grund haben.

Wenn du zuerst in ein Byte-Array ("b") einlesen musst, und der Record mit dem Typ TableFuncParam steht ab Index "i", dann gibt es folgende Möglichkeiten (wahrscheinlich noch mehr):

  • Kopieren per Move:
    Code: Alles auswählen
    var
      tfp: TableFuncParam;
    ...
      Move(b[i], tfp, SizeOf(tfp));
     
  • Type-cast des Pointers
    Code: Alles auswählen
    type
      PTableFuncParam = ^TableFuncParam;
    var
      tfp: TableFuncParam;
    ..
      tfp := PTablefuncParam(@b[i])^;
     
    // evtl geht auch:
      tfp := TableFuncParam(@b[i]^);

Bei dir ist tfp keine einzelne Variable, sondern Element eines Array of TableFuncParam. In diesem Fall ersetze im obigen Fall tfp durch das entsprechende Array-Element tfp[index].
wp_xyz
 
Beiträge: 2569
Registriert: 8. Apr 2011, 08:01

Beitragvon Helios » 14. Jan 2018, 20:56 Re: Records aus einem Byte Array herauslesen?

Hallo wp_xyz
hallo Mathias,

besten Dank für Eure Rückmeldungen.
Kurz zu Eurer Frage: Erst zur Laufzeit weiss ich, wie der Byte Stream zu interpretieren ist.
Beim ersten lesen/parsen der Datei (MDF = Measurement Data Format von Vector) lege ich
daher die Daten "neutral" als Array Of Byte ab (habe Sie aus der Datei mit ByteRead ausgelesen
klappte bisher alles vorzüglich) um Sie später dann ohne erneuten Datei Lesezugriff die
Daten in den verschiedenen Record (Arrays) zu kopieren.

@wp_xyz:
Der Ansatz
...
tfp[j] := PTablefuncParam(@b[i])^;
...
compiliert sauber, nur funktioniert der Zugriff auf tfp[i] elemente nicht über z.B. low(tfp) bzw. high(tfp).
Darüber bekomme ich statt dessen die Werte low(b) = 0 und high(b) = 79 (in dem Byte Array sind 80 Bytes die passen für 2 ftp Records),
Ich glaube ich bin mit Eurer Hilfe nahe dran und werde in den nächsten Tagen diesbgl. weiterforschen.
Entsprechendes Ergebnis melde ich hier dann zurück.
Danke nochmal für Eure Unterstützung und Gruß
Arne
Helios
 
Beiträge: 12
Registriert: 29. Jun 2011, 21:36
Wohnort: Leonberg
OS, Lazarus, FPC: Lazarus 1.8.2 Windows 7 64Bit / Lazarus 1.8.0 Debian 9 „Stretch" 64Bit | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 14. Jan 2018, 21:01 Re: Records aus einem Byte Array herauslesen?

Code: Alles auswählen
var
TFPArray: Array Of TableFuncParam;
ByteArray: Array Of Bytes;


Das sind dynamische Arrays, die kannst du einfach casten:
Code: Alles auswählen
TBytes(TFPArray) := ByteArray
Warf
 
Beiträge: 920
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon wp_xyz » 14. Jan 2018, 22:02 Re: Records aus einem Byte Array herauslesen?

Helios hat geschrieben:@wp_xyz:
Der Ansatz
...
tfp[j] := PTablefuncParam(@b[i])^;
...
compiliert sauber, nur funktioniert der Zugriff auf tfp[i] elemente nicht über z.B. low(tfp) bzw. high(tfp).
Darüber bekomme ich statt dessen die Werte low(b) = 0 und high(b) = 79 (in dem Byte Array sind 80 Bytes die passen für 2 ftp Records),

i und j sind natürlich unterschiedliche Indizes. i läuft in dem Byte-Array b - jedes Byte ein neuer Index. j dagegen durchläuft das TableFuncParam-Array. Wenn die TableFuncParam Elemente unmittelbar hintereinander im Byte-Array stecken, dann wird j immer dann erhöht, wenn i um 40 Byte (= SizeOf(TablefuncParam)) angewachsen ist. Schau dir mal folgenden (ungetesteten) Code an

Code: Alles auswählen
var
  i, j: Integer;
  b: array of byte;
  tfp: array of TableFuncParam;
begin
  SetLength(tfp, Length(b) div SizeOf(TableFuncParam));
  i := 0;
  for j := Low(ffp) to High(tfp) do begin
    tfp[j] := PTableFuncParam(@b[i])^;
    inc(i, Sizeof(TableFuncParam));
  end;
end;
wp_xyz
 
Beiträge: 2569
Registriert: 8. Apr 2011, 08:01

Beitragvon Mathias » 14. Jan 2018, 22:23 Re: Records aus einem Byte Array herauslesen?

Erst zur Laufzeit weiss ich, wie der Byte Stream zu interpretieren ist.

Du kannst problemlos, zur Laufzeit sagen, was und wo du etwas aus den Strem holen willst.
In diesem Beispiel öffne ich die project1.lpr, und hole den Record, dort wo das Wort "Project1" steht.
Code: Alles auswählen
program Project1;     
uses
  Classes;
 
var
  fs: TFileStream;
  r: record
    a, b, c, d, e, f, g, h: char;
  end;
 
begin
  fs := TFileStream.Create('project1.lpr', fmOpenReadWrite);
  fs.Position := 8;
  fs.Read(r, 8);
 
  with r do begin
    WriteLn(a, b, c, d, e, f, g, h);
  end;
 
  fs.Free;
end.

Ich verwende nur Pointer und Zeiger, wen es nicht anders geht.
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4109
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon Warf » 14. Jan 2018, 22:26 Re: Records aus einem Byte Array herauslesen?

wp_xyz hat geschrieben:i und j sind natürlich unterschiedliche Indizes. i läuft in dem Byte-Array b - jedes Byte ein neuer Index. j dagegen durchläuft das TableFuncParam-Array. Wenn die TableFuncParam Elemente unmittelbar hintereinander im Byte-Array stecken, dann wird j immer dann erhöht, wenn i um 40 Byte (= SizeOf(TablefuncParam)) angewachsen ist. Schau dir mal folgenden (ungetesteten) Code an

Code: Alles auswählen
var
  i, j: Integer;
  b: array of byte;
  tfp: array of TableFuncParam;
begin
  SetLength(tfp, Length(b) div SizeOf(TableFuncParam));
  i := 0;
  for j := Low(ffp) to High(tfp) do begin
    tfp[j] := PTableFuncParam(@b[i])^;
    inc(i, Sizeof(TableFuncParam));
  end;
end;


Kopieren geht auch einfach
Code: Alles auswählen
type
  TIrgendwasArray: array of TIrgendwas;
var
  bytes: TBytes;
  IwasArray: TIrgendwasArray;
begin
  IwasArray := TIrgendwasArray(bytes);
  SetLength(IwasArray, Length(IwasArray));
 
Warf
 
Beiträge: 920
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon wp_xyz » 14. Jan 2018, 22:33 Re: Records aus einem Byte Array herauslesen?

Warf hat geschrieben:Kopieren geht auch einfach
Code: Alles auswählen
type
  TIrgendwasArray: array of TIrgendwas;
var
  bytes: TBytes;
  IwasArray: TIrgendwasArray;
begin
  IwasArray := TIrgendwasArray(bytes);
  SetLength(IwasArray, Length(IwasArray));
 

Da steig ich nicht durch. Was soll es bringen, wenn ich die Länge eines Arrays auf den Wert setze, den es schon hat?
wp_xyz
 
Beiträge: 2569
Registriert: 8. Apr 2011, 08:01

Beitragvon Warf » 14. Jan 2018, 22:43 Re: Records aus einem Byte Array herauslesen?

Bei dem Cast wird nur der Arraypointer übergeben, und der RefCount erhöt.
Setlength garantiert das das ergebnis die RefCount 1 hat. Da die RefCount aber größer 1 ist, wird der Speicher kopiert, und ein neues Array mit RefCount 1 erzeugt
Warf
 
Beiträge: 920
Registriert: 23. Sep 2014, 16:46
Wohnort: Aachen
OS, Lazarus, FPC: Mac OSX 10.11 | Win 10 | FPC 3.0.0 | L trunk | 
CPU-Target: x86_64, i368, ARM
Nach oben

Beitragvon Helios » 14. Jan 2018, 22:58 Re: Records aus einem Byte Array herauslesen?

Hallo Gentlemen,

vielen Dank für Euren super Support am Sonntag Abend!

Hier noch der Ausschnitt aus meinem Source welches ich mit Eurer Hilfe erstellen konnte
(wobei ich das zusätzlich schöne inc() von wp_xyz als Ersatz für meine aufwändigere (Index) Multiplikation gerne verwenden/übernehmen werde.
Wieder was gelernt!:-)

type
...
ASAM_MCD2_Text_TableFuncParam = packed record // type 11
Value1: double;
ByteArray: array [0..31] of byte;
end;
...
PASAM_MCD2_Text_TableFuncParam = ^ASAM_MCD2_Text_TableFuncParam;

TFunc = class
public
...
TableValues: array of ASAM_MCD2_Text_TableFuncParam;
...
end;

constructor TFunc.Create(param: array of byte; size: word);
var
i: word;
begin
SetLength(TableValues, size);

for i := low(TableValues) to high(TableValues) do
TableValues[i] := PASAM_MCD2_Text_TableFuncParam(@param[i*SizeOf(ASAM_MCD2_Text_TableFuncParam)])^;
end;

Nochmals Danke!
Falls jemand noch eine Lösung hat, bei dem gar keine Iteration über die TableValues[i]
(und kein Aufruf von SetLength?) notwendig ist (evtl. der Ansatz von Warf?)
Wäre ich daran auch sehr interessiert, aber schon so ist das schon deutlich schöner als das was ich vorher
zusammenprogramiert habe.
Gute Nacht und Euch allen einen schönen Start in die Woche!
Gruß

Arne
Helios
 
Beiträge: 12
Registriert: 29. Jun 2011, 21:36
Wohnort: Leonberg
OS, Lazarus, FPC: Lazarus 1.8.2 Windows 7 64Bit / Lazarus 1.8.0 Debian 9 „Stretch" 64Bit | 
CPU-Target: 64Bit
Nach oben

Beitragvon Mathias » 14. Jan 2018, 23:09 Re: Records aus einem Byte Array herauslesen?

Falls jemand noch eine Lösung hat, bei dem gar keine Iteration über die TableValues[i]

Was haltet dich vom TFileStream ab ?
Mit Lazarus sehe ich gün
Mit Java und C/C++ sehe ich rot
Mathias
 
Beiträge: 4109
Registriert: 2. Jan 2014, 17:21
Wohnort: Schweiz
OS, Lazarus, FPC: Linux (die neusten Trunc) | 
CPU-Target: 64Bit
Nach oben

Beitragvon wp_xyz » 14. Jan 2018, 23:32 Re: Records aus einem Byte Array herauslesen?

Warf hat geschrieben:Bei dem Cast wird nur der Arraypointer übergeben, und der RefCount erhöt.
Setlength garantiert das das ergebnis die RefCount 1 hat. Da die RefCount aber größer 1 ist, wird der Speicher kopiert, und ein neues Array mit RefCount 1 erzeugt


Schön zu wissen. Aber ehrlich gesagt - vor solchem Code halte ich Abstand, da verkommt die schön leserliche Programmiersprache Pascal zur Geheimschrift a la C & Konsorten.
wp_xyz
 
Beiträge: 2569
Registriert: 8. Apr 2011, 08:01

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Freepascal



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 5 Gäste

porpoises-institution
accuracy-worried