[GELOEST] Einlesen von Binärdaten

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Einlesen von Binärdaten

Beitrag von wp_xyz »

Nein, alles in Ordnung:
- Record als "packed" deklarieren.
- Hinter "Name" (128 bytes) 2 Füllbytes deklarieren
- Die Int16 durch Int32 (LongInt) ersetzen.

Dies hier liest die Datei problemlos ein und zeigt vernünftig aussehende Werte (Formular mit Memo):

Code: Alles auswählen

 
procedure TForm1.FormCreate(Sender: TObject);
begin
  ReadFile('sr500.rlx');
end;
 
procedure TForm1.ReadFile(AFilename: String);
const
  MAXGANG = 7;
  MAXPNT = 60;
type
  TRoadLoadData = packed record
    Vers : array[0..5] of char;
    Name : array[0..127] of char;
    Filler: Word;
    Gewicht : double;   { Gewicht der Maschine in kg }
    sx, sy : double;    { Koordinaten des Schwerpunkts [m]}
    Radstand : double;  { Radstand [m] }
    Flaeche : double;   { Windwiderstandsflaeche [m²] }
    cw : double;        { Luftwiderstandsbeiwert (cw-Wert) [-] }
    Umfang : double;    { Radumfang Antriebsrad [m] }
    mu : double;        { Haftreibungskoeffizient Rad-Strasse [-] }
    { Getriebe- und Antriebsdaten }
    i_prim : double;
    z_ritzel : LongInt; { Anzahl der Zaehne auf dem Ritzel [-] }
    z_blatt : LongInt;  { Anzahl der Zaehne auf dem Kettenblatt [-] }
    n_gaenge : LongInt; { Anzahl Gaenge [-] }
    i_getriebe : array[1..MAXGANG] of double;
    i_ges : array[1..MAXGANG] of double;
    n_kuppl : double;   { Einkuppeldrehzahl [U/min] }
    n_schalt : double;  { Schaltdrehzahl [U/min] }
    { Kennliniendaten }
    pnt : integer;
    n : array[1..MAXPNT] of double;   { Array der Drehzahlen d. Stuetzpunkte }
    n_max : double;     { Maximaldrehzahl }
    p : array[1..MAXPNT] of double;       { Array mit der Leistung dazu }
    p_max : double;               { maximale Leistung }
    n_p_max : double;     { Drehzahl von P_max }
    m : array[1..MAXPNT] of double;       { Array Drehmoment-Kennlinie }
    m_max : double;               { maximales Drehmoment }
    n_m_max : double;     { Drehzahl von M_max }
    { Umwelt-Daten }
    Steigung : double;  { Hangsteigung [%] }
    Wind : double;                { Windgeschwindigkeit [km/h] }
    Gew_Fahrer : double;  { Gewicht des Fahrers [kg] }
    Gew_Zuladung : double;  { Zuladung [kg] }
  end;
 
var
  data: TRoadLoadData;
  stream: TStream;
  p: PChar;
  i: Integer;
  s: String;
begin
  stream := TFileStream.Create(AFileName, fmOpenRead);
  try
    stream.ReadBuffer(data, SizeOf(data));
 
    p := PChar(data.Vers);
    Memo1.Lines.Add('Vers: ' + StrPas(p));
 
    p := PChar(data.Name);
    Memo1.Lines.Add('Name: ' + StrPas(p));
 
    Memo1.Lines.Add('Gewicht: ' + FloatToStr(data.Gewicht));
    Memo1.Lines.Add('sx : ' + FloatToStr(data.sx));
    Memo1.Lines.Add('sy: ' + FloatToStr(data.sy));
    Memo1.Lines.Add('radstand: ' + FloatToStr(data.radstand));
    Memo1.Lines.Add('flaeche: ' + FloatToStr(data.flaeche));
    Memo1.Lines.Add('cw: '+FloatToStr(data.cw));
    Memo1.Lines.Add('Umfang: '+FloatToStr(data.Umfang));
    Memo1.Lines.Add('mu: '+FloatToStr(data.mu));
    Memo1.Lines.Add('');
    Memo1.Lines.Add('GETRIEBE- UND ANTRIEBSDATEN');
    Memo1.Lines.Add('i_prim: ' + FloatToStr(data.i_prim));
    Memo1.Lines.Add('z_ritzel: '+IntTostr(data.z_ritzel));
    Memo1.Lines.Add('z_blatt: '+IntToStr(data.z_blatt));
    Memo1.Lines.Add('n_gaenge: '+ IntToStr(data.n_gaenge));
    for i:=1 to MAXGANG do begin
      s := 'i_getriebe[' + IntToStr(i) + ']: ' + FloatToStr(data.i_getriebe[i]);
      if i > data.n_gaenge then
        s := s + '  !!! undefiniert !!!';
      Memo1.Lines.Add(s);
    end;
    for i:=1 to MAXGANG do
    begin
      s := 'i_ges[' + IntToStr(i) + ']: ' + FloatToStr(data.i_ges[i]);
      if i > data.n_gaenge then
        s := s + '  !!! undefiniert !!!';
      Memo1.Lines.Add(s);
    end;
    Memo1.Lines.Add('n_kuppl: ' + FloatToStr(data.n_kuppl));
    Memo1.Lines.Add('n_schalt: ' + FloatToStr(data.N_schalt));
    Memo1.Lines.Add('');
    Memo1.Lines.Add('KENNLINIENDATEN');
    Memo1.Lines.Add('pnt: ' + IntToStr(data.pnt));
    for i:=1 to MAXPNT do
    begin
      s := 'n[' + IntToStr(i) + ']: ' + FloatToStr(data.n[i]);
      if i > data.pnt then
        s := s + ' !!! undefiniert !!!';
      Memo1.Lines.Add(s);
    end;
    Memo1.Lines.Add('n_max: ' + FloatToStr(data.n_max));
    for i:=1 to MAXPNT do
    begin
      s := 'p[' + IntToStr(i) + ']: ' + FloatToStr(data.p[i]);
      if i > data.pnt then
        s := s + ' !!! undefiniert !!!';
      Memo1.Lines.Add(s);
    end;
    Memo1.Lines.Add('p_max: ' + FloatToStr(data.p_max));
    Memo1.Lines.Add('n_p_max: ' + FloatToStr(data.n_p_max));
    Memo1.Lines.Add('');
    Memo1.Lines.Add('UMWELTDATEN');
    Memo1.Lines.Add('Steigung: ' + FloatToStr(data.Steigung));
    Memo1.Lines.Add('Wind: ' + FloatToStr(data.Wind));
    Memo1.Lines.Add('Gew_Fahrer: ' + FloatToStr(data.Gew_Fahrer));
    Memo1.Lines.Add('Gew_Zuladung: ' + FloatToStr(data.Gew_Zuladung));
  finally
    stream.Free;
  end;
end;   

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Einlesen von Binärdaten

Beitrag von Mathias »

Der Übeltäter war anscheinend, das ein normaler Record, gar nichts packt und der packed record dies sehr gründlich macht, und C macht eine Mischung aus beiden.
Darum die beiden Füllbytes.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

Vielen Dank für Eure Hilfe. Ich hätte bestimmt noch einige Zeit gedoktort (und wahrscheinlich dann doch Wert für Wert eingelesen). Den Verdacht, dass Pascal binär anders speichert als C hatte ich ja von Anfang an. Aber da wäre noch viel rum zu testen gewesen. :roll:

Aber die große Lehre bleibt: am besten, man speichert solche Daten in irgendeinem ASCII-Daten-Format :wink:

Danke,

Photor

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Einlesen von Binärdaten

Beitrag von wp_xyz »

photor hat geschrieben:und wahrscheinlich dann doch Wert für Wert eingelesen

Hätte auch nichts gebracht, wenn du die von C eingefügten beiden Füllbytes nach dem Namen nicht berücksichtigt hättest.

Michl
Beiträge: 2505
Registriert: Di 19. Jun 2012, 12:54

Re: Einlesen von Binärdaten

Beitrag von Michl »

photor hat geschrieben:Aber die große Lehre bleibt: am besten, man speichert solche Daten in irgendeinem ASCII-Daten-Format
Off-Topic: Ich würde vermutlich eher eine Datenbank damit füttern.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
photor
Beiträge: 443
Registriert: Mo 24. Jan 2011, 21:38
OS, Lazarus, FPC: Arch Linux: L 2.2.6 FPC 3.2.2 (Gtk2)
CPU-Target: 64Bit

Re: Einlesen von Binärdaten

Beitrag von photor »

Michl hat geschrieben:Off-Topic: Ich würde vermutlich eher eine Datenbank damit füttern.


DAS wäre dann endgültig mit Kanonen auf Spatzenkinder schießen :D

Ciao,

Photor

PS: Thread auf "Geloest" gesetzt

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: [GELOEST] Einlesen von Binärdaten

Beitrag von Mathias »

Den Verdacht, dass Pascal binär anders speichert als C hatte ich ja von Anfang an.

Das hier ist noch heilig, probiere mal Daten zwischen Pascal und Java auszutauschen, da bin ich auch mal fast die Wände hoch gegangen.
Das einte System hat bigendian und das ander littleendian.
Ich wollte Vertex-Daten, welche ich mit Lazarus erzeugte in einer Android-App nutzen. Unter Java war ich da auch neu, und das Forum zu Java eine Katastrophe, nicht zu vergleichen mit dem Forum da.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Komoluna
Beiträge: 565
Registriert: So 26. Aug 2012, 09:03
OS, Lazarus, FPC: Windows(10), Linux(Arch)
CPU-Target: 64Bit

Re: [GELOEST] Einlesen von Binärdaten

Beitrag von Komoluna »

Mathias hat geschrieben:
Den Verdacht, dass Pascal binär anders speichert als C hatte ich ja von Anfang an.

Das hier ist noch heilig, probiere mal Daten zwischen Pascal und Java auszutauschen, da bin ich auch mal fast die Wände hoch gegangen.
Das einte System hat bigendian und das ander littleendian.
Ich wollte Vertex-Daten, welche ich mit Lazarus erzeugte in einer Android-App nutzen. Unter Java war ich da auch neu, und das Forum zu Java eine Katastrophe, nicht zu vergleichen mit dem Forum da.

Das problem hatte ich auch letzens, als ich dabei war Minecraft Welten einzulesen/zu speichern. Das ist echt eine Qual.

MFG

Komoluna
Programmer: A device to convert coffee into software.

Rekursion: siehe Rekursion.

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: [GELOEST] Einlesen von Binärdaten

Beitrag von wp_xyz »

Um das Thema abzuschließen: Man kann sich das explizite Einfügen von Füllbytes in die Recorddefinition sparen, indem man, wie weiter oben angedeutet, die Direktive {$PackRecords 4} verwendet; der Typ TRoadLoadData ist dann nur als "record", nicht mehr als "packed record" zu deklarieren. Das oben verwendete {$Packrecords C} führt bei mir zum Absturz.

Allerdings weiß ich nicht, wie die Direktive gilt, wenn mehrere Alignments in verschiedenen Records vorkommen, also: 1.Record soll {$PackRecords 4} haben, 2.Record soll als "packed record" deklariert sein (d.h. {$PackRecords 1}), etc. Gilt das Datei-weit, oder bis zum nächsten $Packrecords?

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: [GELOEST] Einlesen von Binärdaten

Beitrag von Mathias »

die Direktive {$PackRecords 4} verwendet; der Typ TRoadLoadData ist dann nur als "record", nicht mehr als "packed record" zu deklarieren.

Habe es gerade probiert, und es geht ?

Beim experimentieren oben ist mit aufgefallen, das die Records gleich aussehen, egal ob ich 32 oder 64Bit kompiliere.
Müsste es bei einmal eine 4Byte und einmal eine 8Byte Ausrichtung haben ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: [GELOEST] Einlesen von Binärdaten

Beitrag von wp_xyz »

Ich denke, wenn du 4-byte Alignment einstellst (oder eben mit packed record die zwei Füllbyte einbaust) ist alles in Ordnung, egal ob 32 oder 64 bit. Du teilst dem 64-Bit Compiler durch die Direktive ja mit, er solle 4-byte Alignment nehmen, obwohl er standardmäßig 8-byte nehmen würde. Und 4-byte Alignment ist das was du brauchst, weil alle Recordelemente in der Datei bei durch 4 teilbaren Offsets beginnen, das sieht man im Hex-Editor.

Antworten