Records aus einem Byte Array herauslesen?
-
- Lazarusforum e. V.
- Beiträge: 106
- Registriert: Mi 29. Jun 2011, 22:36
- OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
- CPU-Target: 64Bit
- Wohnort: Leonberg
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
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
-
- Beiträge: 6165
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Records aus einem Byte Array herauslesen?
Vielleicht hilft dir "absolute" weiter.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Lazarusforum e. V.
- Beiträge: 106
- Registriert: Mi 29. Jun 2011, 22:36
- OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
- CPU-Target: 64Bit
- Wohnort: Leonberg
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
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
-
- Beiträge: 6165
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
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.
Die Daten von einem Stream kannst du sehr einfach in deinen Record schreiben.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
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):
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]^);
-
- Lazarusforum e. V.
- Beiträge: 106
- Registriert: Mi 29. Jun 2011, 22:36
- OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
- CPU-Target: 64Bit
- Wohnort: Leonberg
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
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
-
- Beiträge: 1908
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
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
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;
-
- Beiträge: 6165
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
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 grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
-
- Beiträge: 1908
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
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 anCode: 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));
Re: Records aus einem Byte Array herauslesen?
Warf hat geschrieben:Kopieren geht auch einfachCode: 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?
-
- Beiträge: 1908
- Registriert: Di 23. Sep 2014, 17:46
- OS, Lazarus, FPC: Win10 | Linux
- CPU-Target: x86_64
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
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
-
- Lazarusforum e. V.
- Beiträge: 106
- Registriert: Mi 29. Jun 2011, 22:36
- OS, Lazarus, FPC: Lazarus 2.2.4 Windows 10 64Bit / Lazarus 2.0.12 Debian 11.7 „Bullseye" 64Bit
- CPU-Target: 64Bit
- Wohnort: Leonberg
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
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
-
- Beiträge: 6165
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
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 grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
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.