Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Einlesen einer FORTRAN Binärdatei mit Delphi (https://www.delphipraxis.net/181104-einlesen-einer-fortran-binaerdatei-mit-delphi.html)

Tenobaal 16. Jul 2014 12:35

Einlesen einer FORTRAN Binärdatei mit Delphi
 
Hallo,
für eine Studienarbeit soll ein altes Fortran77 Programm nach Pascal übersetzt werden (Entwicklungsumgebung ist RadStudio XE5).
Momentan hänge ich beim Einlesen von Datensätzen aus Binärdateien.
Zu Testzweck habe ich in Fortran eine Subroutine angelegt, die vier Integerwerte (NPUNKT,NPVAR,NZELLE,NSTR und KPER) in eine Binärdatei schreibt.
Es handelt sich um 32-Bit Integerzahlen, welche bei Fortran als Integer*4 definiert werden. Somit sollte der Fortran Integer*4 dem "normalen" Integer aus Pascal entsprechen!?!
Im nachfolgenden Code-Block ist der zugehörige Fortran-Code abgebildet.
Hinweis: NNET ist das Dateihandle. Das Öffnen und Schließen der Datei ist nicht Bestandteil der Subroutine OUTNET. Es geschieht an einer anderen Stelle im Programm.
Code:
      SUBROUTINE OUTNET
C**********************************************************************
C
C
C
C IMPLICIT
C
      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
C
      COMMON /STEUER/ IERR,LIN,KPER,NPRINT,MPRINT,MAXP,MAXT,IRECH,IB2,
     ,               NSPG,NROT1,NROT2,NSTROM
      COMMON /TEXTE/  TITEL
      COMMON /NETZP/  NPMAX,NPUNKT,NPVAR,NZMAX,NZELLE,NSMAX,NSTR,MMAX
      COMMON /NETZD/  X(10000),Y(10000),A(10000),NUE(20000),SD(20000),
     ,               GAM(20000),
     ,               D(20000),GK(3,20000),NACHBZ(60000),ENDZ(10000),
     ,               NPER(10000),MGEB(20000),
     ,               ECKP(3,20000),RANDZ(3,20000),RANDS(3,20000),
     ,               AP(30000),EP(30000),GL(30000),GR(30000),
     ,               RAND(30000),ZL(30000),ZR(30000)
      COMMON /KONTUR/ GECKP(3,4000),IGECKP
      COMMON /IODEF / VERSIO,NTEST,IKART,NLIST,ND1,INET,NNET,NPLOT,
     ,               NUEPL
C
      DOUBLE PRECISION   NUE,GAM
      COMPLEX*16 A,SD
      CHARACTER*80 TITEL
      REAL*8 VERSIO
      INTEGER*4 NACHBZ,ENDZ,NPER,MGEB,ECKP,RANDZ,RANDS
      INTEGER*4 AP,EP,GL,GR,RAND,ZL,ZR
C
      WRITE (NNET) NPUNKT,NPVAR,NZELLE,NSTR,KPER
C
      RETURN
      END
Nun habe ich mit Delphi eine Prozedure geschrieben, die die erzeugte Fortran Binärdatei einlesen soll. Dabei entsteht allerdings nur Datensalat.
Zuvor habe ich schon mit der Klasse TFileStream gearbeitet und konnte erfolgreich Binärdateien anlegen und einlesen.:wink:
Ich vermute daher, dass Fortran die Binärdatei anders strukturiert? Im Internet konnte ich keine Informationen dazu finden.

MFG Tenobaal

Delphi-Quellcode:
procedure TNetgen.ReadNet(Directory,Filename:String);
var
  Stream:TFileStream;
Begin
Stream:=TFileStream.Create(Directory+Filename+'.NET',fmOpenRead);
try
  try
    //NPUNKT,NPVAR,NZELLE,NSTR,KPER sind vom Datentyp Integer
    Stream.Read(NPUNKT,SizeOf(NPUNKT));
    Stream.Read(NPVAR,SizeOf(NPVAR));
    Stream.Read(NZELLE,SizeOf(NZELLE));
    Stream.Read(NSTR,SizeOf(NSTR));
    Stream.Read(KPER,SizeOf(KPER));
  except
    on E: Exception do
      begin
      ErrorMessagesINOUT.Add('Fehler beim anlegen der Netzdatei ('+Filename+'.NET)');
      ErrorMessagesINOUT.Add(E.ClassName+' Fehler aufgetreten mit Nachricht : '+E.Message);
      end;
  end;
finally
  Stream.Free;
end;

End;

Der schöne Günther 16. Jul 2014 12:45

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Tenobaal (Beitrag 1265653)
Es handelt sich um 32-Bit Integerzahlen, welche bei Fortran als Integer*4 definiert werden. Somit sollte der Fortran Integer*4 dem "normalen" Integer aus Pascal entsprechen!?!

Ich habe noch nie was mit Fortran gemacht, aber eine Suche nach "Fortran integer range" sieht mir eher danach aus, als sei der Typ INTEGER einfach nur ein Byte mit Vorzeichen? INTEGER*4 demnach 32 Bit.

Mavarik 16. Jul 2014 13:27

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Also... Ich mache sowas immer so:

Delphi-Quellcode:
{$A1} // Wichtig

Const
   Recordlaenge = 2245; // Filesize / Recordlaenge passt!

type
    TStruct = Record
                A   : Byte; // Bin ich mir sicher
                B   : Word; // Bin ich mir sicher
                C   : Byte; // Bin ich mir sicher
                Rest : Array[1..Recordlaenge-4 {Sizeof A-C} ] of Byte;
              end;
var
  F : File;

Procedure Readit;
var
  Struct : TStruct;
begin
  Assignfile(F,'Bla.dat');
  Reset(F,1);
  Blockread(F,Struct,sizeof(Struct));
  Closefile(F);
end;
So kannst Du schön mit dem Debugger durch gehen und im ganz schnell alles ändern.

Mavarik

Tenobaal 16. Jul 2014 13:48

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Ich habe mit Delphi und Fortran jweils die Integerzahl "735" (Dezimal) in eine Binärdatei geschrieben. Beide Dateien wurden dann mit nem Hex-Editor geöffnet.

Fortran:
Code:
04 DF 02 00 00 04
Delphi:
Code:
DF 02 00 00
Ich habe zuvor noch nie mit einem Hex-Editor gearbeitet :oops: ,aber meine "735" Dezimal entspricht 2DF (Hex). 2DF steht allerdings in keiner der Dateien :shock:
Abgesehen davon, ist im Fortran-Code am Anfang und am Ende jeweils zusätzlich ein '04' (Hex) vorhanden. Laut ASCII-Tabelle bedeutet dies dem Zeichen 'EOT' - End of Transmission.
Ich versuche mal die Position beim lesen der Datei zu verändern, sodass meine Delphi Prozedur erst beim 2 Byte anfängt die Daten zu lesen.

Der schöne Günther 16. Jul 2014 13:54

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Deine 00 00 02 DF ist doch die DF 02 00 00, nur zweimal umgedreht, oder?

(00 00) (02 DF) -> (02 DF) (00 00) -> (DF 02) (00 00)

Tenobaal 16. Jul 2014 13:56

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Problem gelöst. Ich habe "Stream.Position:=1;" vor den ersten Read-Befehl meiner Delphi Prozedur gehangen, damit erst ab dem 2 Byte gelesen wird :lol:

Uwe Raabe 16. Jul 2014 14:22

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Tenobaal (Beitrag 1265666)
Problem gelöst. Ich habe "Stream.Position:=1;" vor den ersten Read-Befehl meiner Delphi Prozedur gehangen, damit erst ab dem 2 Byte gelesen wird :lol:

Das sieht mir aber nicht nach einer generellen Lösung aus. Zeig doch mal den Hexdump der gesamten Fortran-Datei oder hänge sie hier an.

Tenobaal 16. Jul 2014 15:54

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
War auch zu früh gefreut. Bei mehreren Datentypen in der Binärdatei funktioniert die Lösung nicht mehr. Scheinbar werden weitere EOT-Zeichen wahllos eingestreut :wink:

Klaus01 16. Jul 2014 16:02

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
.. kann es sein, dass jedes Integer*4 Datenfeld mit 04 beginnt oder ist es ein Feldtrenner?

Code:
04 DF 02 00 00 04
Anhand der wenigen Daten ist das schwer zu erkennen.

Grüße
Klaus

Uwe Raabe 16. Jul 2014 16:11

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Tenobaal (Beitrag 1265692)
Scheinbar werden weitere EOT-Zeichen wahllos eingestreut :wink:

Na eben nicht wahllos! Aber wir können anhand der gezeigten sechs Bytes natürlich auch nur was ahnen.

p80286 16. Jul 2014 16:31

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1265668)
Das sieht mir aber nicht nach einer generellen Lösung aus. Zeig doch mal den Hexdump der gesamten Fortran-Datei oder hänge sie hier an.

:thumb::thumb::thumb:

Gruß
K-H

Tenobaal 16. Jul 2014 18:46

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Hier eine Funktion die eine Double, zwei Integer Zahlen und ein Array der Länge 3 vom Datentyp Char in eine Binärdatei schreibt.
Inhalt der Binärdatei aus dem Hexeditor:
Code:
13000000000000F03F020000000200000041424313
Programmcode:
Code:
      SUBROUTINE OUTNET
C**********************************************************************
C
C
C
C IMPLICIT
C
      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
C
      COMMON /STEUER/ IERR,LIN,KPER,NPRINT,MPRINT,MAXP,MAXT,IRECH,IB2,
     ,               NSPG,NROT1,NROT2,NSTROM
      COMMON /TEXTE/  TITEL
      COMMON /NETZP/  NPMAX,NPUNKT,NPVAR,NZMAX,NZELLE,NSMAX,NSTR,MMAX
      COMMON /NETZD/  X(10000),Y(10000),A(10000),NUE(20000),SD(20000),
     ,               GAM(20000),
     ,               D(20000),GK(3,20000),NACHBZ(60000),ENDZ(10000),
     ,               NPER(10000),MGEB(20000),
     ,               ECKP(3,20000),RANDZ(3,20000),RANDS(3,20000),
     ,               AP(30000),EP(30000),GL(30000),GR(30000),
     ,               RAND(30000),ZL(30000),ZR(30000)
      COMMON /KONTUR/ GECKP(3,4000),IGECKP
      COMMON /IODEF / VERSIO,NTEST,IKART,NLIST,ND1,INET,NNET,NPLOT,
     ,               NUEPL

      DOUBLE PRECISION   NUE,GAM
      COMPLEX*16 A,SD,AComplex
      CHARACTER*3 TITEL
      REAL*8 VERSIO
      INTEGER*4 NACHBZ,ENDZ,NPER,MGEB,ECKP,RANDZ,RANDS
      INTEGER*4 AP,EP,GL,GR,RAND,ZL,ZR

      ADOUBLE=1.0 !Double 64-Bit
      NINTEGER=2  !Integer 32-Bit
      TITEL='ABC' ! Array of Char
     
      WRITE (NNET) ADOUBLE,NINTEGER,NINTEGER,TITEL !Schreibe in Binärdatei
      RETURN
      END

Uwe Raabe 16. Jul 2014 18:54

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Die $13 sind offensichtlich die Länge des Records (19 Zeichen). Warum die am Ende nochmal kommt, weiß ich auch nicht. Mach doch mal eine Datei mit mehreren Datensätzen. (Mit Fortran hatte ich das letzte Mal vor 40 Jahren zu tun...)

BUG 16. Jul 2014 23:43

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1265710)
Die $13 sind offensichtlich die Länge des Records (19 Zeichen). Warum die am Ende nochmal kommt, weiß ich auch nicht.

Ein Suchergebnis hat Rückwärtsspringen über Records vermutet ... würde Sinn machen.

@tenobaal: Du scheinst den implementierungsabhängigen Unformatted-Mode zu benutzen, insofern wirst du keine Lösung finden, die mit allen Fortran-Compilern kompatibel ist.

Uwe Raabe 17. Jul 2014 08:17

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von BUG (Beitrag 1265726)
Zitat:

Zitat von Uwe Raabe (Beitrag 1265710)
Die $13 sind offensichtlich die Länge des Records (19 Zeichen). Warum die am Ende nochmal kommt, weiß ich auch nicht.

Ein Suchergebnis hat Rückwärtsspringen über Records vermutet ... würde Sinn machen.

Das wäre denkbar. Ein ähnliches Format hatte ich schon mal bei Daten für Magnetbänder.

Mavarik 17. Jul 2014 10:13

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Also für mich sieht das ganz und gar nicht nach eine Binärdatei aus...

Schau Dir mal das hier an
...

Mavarik

Blup 17. Jul 2014 10:15

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
ich würde das im Prinzip so aufbauen:
Delphi-Quellcode:
unit FortranWriter;

interface

type
  TFortranObjectWriter = abstract class(TObject)
  protected
    class procedure GetDataObjectClass: TClass; virtual; abstract;
    class procedure WriteToBuffer(ABuffer: TCustomStream; AValue: Double); overload:
    class procedure WriteToBuffer(ABuffer: TCustomStream; AValue: Integer); overload:
    class procedure Register;
    class procedure UnRegister;
  public
    class property DataObjectClass: TClass read GetDataObjectClass;
    class procedure WriteObjectToBuffer(ABuffer: TCustomStream; AObject: TObject); virtual; abstract;
  end;

  TFortranObjectWriterClass = class of TFortranObjectWriter;

  TFortranWriter = class(TObject)
    constructor Create(AStream: TCustomStream);
    destructor Destroy;
  private
    FBuffer: TMemmoryStream;
    FStream: TCustomStream;
    class var FObjectWriter: TClassList;
  protected
    class procedure RegisterObjectWriter(AClass: TFortranObjectWriterClass);
    class procedure UnRegisterObjectWriter(AClass: TFortranObjectWriterClass);
    class procedure GetObjectWriter(AClass: TClass): TFortranObjectWriterClass;
  public
    procedure Write(AObject: TObject); virtual;
  end;

implementation

constructor TFortranWriter.Create(AStream: TCustomStream);
begin
  inherited Create;
 
  FStream := AStream;
  FBuffer := TMemmoryStream.Create;
end;

destructor TFortranWriter.Destroy;
begin
  FBuffer.Free;

  inherited;
end;

procedure TFortranWriter.Write(AObject: TObject);
var
  ObjectWriter: TFortranObjectWriterClass;
  ByteSize: Byte;
begin
  FBuffer.Clear;
  ObjectWriter := GetObjectWriter(AObject.Class);
  if not Assigned(ObjectWriter) then
    raise Exception.Create('...');

  ObjectWriter.WriteObjectToBuffer(FBuffer, AObject);
  if FBuffer.Size = 0 then
    raise Exception.Create('...');
  if FBuffer.Size > 255 then
    raise Exception.Create('...');

  ByteSize := FBuffer.Size;

  FStream.Write(ByteSize, SizeOf(ByteSize));
  FBuffer.WriteToStream(FStream);
  FStream.Write(ByteSize, SizeOf(ByteSize));
end;

class procedure TFortranWriter.RegisterObjectWriter(AClass: TFortranObjectWriterClass);
begin
  if not Assigned(FObjectWriter) then
    FObjectWriter := TClassList.Create;

  FObjectWriter.Add(AClass);
end;

class procedure TFortranWriter.UnregisterObjectWriter(AClass: TFortranObjectWriterClass);
begin
  if not Assigned(FObjectWriter) then
    Exit;

  FObjectWriter.Remove(AClass);

  if FObjectWriter.Count = 0 then
    FreeAndNil(FObjectWriter);
end;

class procedure TFortranWriter.GetObjectWriter(AClass: TClass): TFortranObjectWriterClass;
begin
  if Assigned(FObjectWriter) then
  begin
    for i := FObjectWriter.Count - 1 downto 0 do
    begin
      Result := TFortranObjectWriter(FObjectWriter[i]);
      if AClass is Result.DataObjectClass then
        Exit;
    end;
  end;
  Result := nil;
end;

class procedure TFortranObjectWriter.WriteToBuffer(ABuffer: TCustomStream; AValue: Double);
begin
  ABuffer.Write(AValue, SizeOf(AValue));
end;

class procedure TFortranObjectWriter.WriteToBuffer(ABuffer: TCustomStream; AValue: Integer);
begin
  ABuffer.Write(AValue, SizeOf(AValue));
end;

class procedure TFortranObjectWriter.Register;
begin
  TFortranWriter.Register(Self);
end;

class procedure TFortranObjectWriter.UnRegister;
begin
  TFortranWriter.UnRegister(Self);
end;

end.
Delphi-Quellcode:
unit MyDataObject;

interface

type
  TMyDataObject = class(TObject)
  private
    FA: Double;
    FB: Integer;
    FC: Integer;
  published
    property A: Double read FA write FA;
    property B: Integer read FB wirte FB;
    property C: Integer read FC write FC;
  end;
Delphi-Quellcode:
unit FortranMyDataObject;

interface

implementation

type
  TMyDataObjectFortranWriter = class(TFortranObjectWriter)
  protected
    class procedure GetDataObjectClass: TClass; override;
  public
    class procedure WriteObjectToBuffer(ABuffer: TCustomStream; AObject: TObject); override;
  end;

class procedure TMyDataObjectFortranWriter.GetDataObjectClass: TClass;
begin
  Result := TMyDataObject;
end;

class procedure TMyDataObjectFortranWriter.WriteObjectToBuffer(ABuffer: TCustomStream; AObject: TObject);
begin
  with TMyDataObject(AObject) do
  begin
    WriteToBuffer(ABuffer, A);
    WriteToBuffer(ABuffer, B);
    WriteToBuffer(ABuffer, C);
  end;
end;

initialization
  TMyDataObjectFortranWriter.Register;

finalization
  TMyDataObjectFortranWriter.UnRegister;

end.
Delphi-Quellcode:
MyObject := nil;
Stream  := nil;
Writer  := nil;
try
  Stream := TFileStream.Create('MyFortranFile.bin');
  Writer := TFortranWriter.Create(Stream);
  MyObject := TMyDataObject.Create;
  MyObject.A := 1;
  MyObject.B := 2;
  MyObject.C := 3;
  Writer.Write(MyObject);
  MyObject.A := 4;
  MyObject.B := 5;
  MyObject.C := 6;
  Writer.Write(MyObject);
finally
  Writer.Free;
  Stream.Free;
  MyObject.Free;
end;

Mavarik 17. Jul 2014 10:45

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Tenobaal (Beitrag 1265709)
Hier eine Funktion die eine Double, zwei Integer Zahlen und ein Array der Länge 3 vom Datentyp Char in eine Binärdatei schreibt.
Inhalt der Binärdatei aus dem Hexeditor:
Code:
13000000000000F03F020000000200000041424313

OK Formatieren wir das mal so das man es lesen kann...

Code:
13 00 00 00 00 00 00 F0 3F 02 00 00 00 02 00 00 00 41 42 43 13
Lassen wir mal die $13 vor und nach dem Datensatz außer acht...

Dann schreibt diese kleine Delphi Programm das gleiche weg... (Oder liest es ein).
Auch ohne eine Monster-Class dafür zu Programmieren. :stupid:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
{$A1}

type
  TB = record
         Len1 : byte;
         A : Double;
         C,
         D : Integer;
         S : array[1..3] of AnsiChar;
         Len2 : byte;
       end;

// 13 00 00 00 00 00 00 F0 3F 02 00 00 00 02 00 00 00 41 42 43 13

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    B : TB;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  F : File;
begin
  Assignfile(F,'Test.net');
  rewrite(F,1);
  B.Len1 := $13;
  B.Len2 := $13;
  B.A := 1.0;
  B.C := 2;
  B.D := 2;
  B.S[1] := 'A';
  B.S[2] := 'B';
  B.S[3] := 'C';
  Blockwrite(F,B,Sizeof(B));
  Closefile(F);
end;

end.
Aber das wird trotzdem nicht zielführend sein, da der Text ABC keine längen Informationen hat...
Es sei den, Texte werden mit einem $13 beendet.. Also kein längenbyte und nicht 0 terminiert.
Oder das letzte $13 ist einfach ein CR weil Datei nicht als Bin Datei geöffnet wurde.

Boh... Mach doch mal ein richtiges Beispiel und fülle die Daten mit einem Pattern.

Delphi-Quellcode:
var
  B : Byte;
  W : Word;
  L : Integer;
  S1 : String
  S2 : String;
  N : Byte;
begin
  B := $55;
  W := $3388;
  L := $11223344;
  S1 := 'Das ist ein cooler Text';
  S2 := 'Noch einer';
  N := $99;
  ...
end;
In Fortran natürlich und bitte 3x hinter einander weg schreiben... und bitte erst dem Link aus meinen mein Posting #16 lesen.

Mavarik

Sir Rufo 17. Jul 2014 10:53

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Mavarik (Beitrag 1265750)
Also für mich sieht das ganz und gar nicht nach eine Binärdatei aus...

Schau Dir mal das hier an
...

Mavarik

Jede Datei ist eine Binär-Datei. Alles andere sind Unterklassen mit einem vereinbarten Format ;)

Mavarik 17. Jul 2014 11:04

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Sir Rufo (Beitrag 1265759)
Jede Datei ist eine Binär-Datei. Alles andere sind Unterklassen mit einem vereinbarten Format ;)

Logisch... Solange wir Informationen noch nicht in Bio-neuronalen-Gel Packs abspeichern...

Siehe...

Mavarik :coder:

Uwe Raabe 17. Jul 2014 11:17

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Der Wiki-Eintrag ist an dieser Stelle irreführend. Es ist wirklich jede Datei eine Binärdatei. Textdateien sind eine Untermenge davon und auch davon gibt es wieder verschiedene Untermengen mit diversen Encodings und Line-Endings.

Fragte doch neulich jemand, warum denn beim Einlesen mit TEncoding.ANSI keine Fehlermeldung käme, wenn man dem Programm eine Unicode-Datei unterjubelt.

Dein BlockRead-Record-Ansatz ist zwar ziemlich Old-School, aber würde hier durchaus funktionieren - wenn die Datensätze wirklich alle gleich lang sind. Das ist aber nicht zwingend der Fall. Unter der Annahme, daß das eine Byte vor und nach den Nutzdaten wirklich die Recordlänge angibt (255 Byte Maximum - unglaublich!), dann würde sich eigentlich eher ein Stream-Wrapper oder ein
Delphi-Quellcode:
class helper for TStream
anbieten.

Mavarik 17. Jul 2014 11:52

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1265762)
Dein BlockRead-Record-Ansatz ist zwar ziemlich Old-School, aber würde hier durchaus funktionieren

Old-School = Good-School; :-D

Eine Binärdatei ist für mich eine 1:1 Entsprechungen eine Speicher-Datenstruktur ohne ausgerichtete Felder -{$A1}. Keine längen Bytes, Trennzeichen, kein ^Z am Ende usw.

Wenn ich ein Byte in eine Datei schreibe, muss die Datei auch nur ein Byte lang sein.
Wenn ich 100 Datensätze mit je 15 Byte weg schreibe muss die Datei auch 1500 Bytes enthalten. Nicht mehr und nicht weniger.

Dann ist es in meinem Sprachgebrauch eine Binärdatei...

Mavarik

Tenobaal 19. Jul 2014 11:26

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Danke euch, ihr habt mir schon sehr weitergeholfen :thumb:
Ich bin heute auf den Beitrag gestoßen http://stackoverflow.com/questions/8...ed-file-format
Zumindest verstehe ich nun, wie die Struktur der Dateien aufgebaut ist.

Namenloser 19. Jul 2014 14:10

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Mavarik (Beitrag 1265754)
Dann schreibt diese kleine Delphi Programm das gleiche weg... (Oder liest es ein).
Auch ohne eine Monster-Class dafür zu Programmieren. :stupid:

2014 noch Leuten dazu zu raten, die alten Pascal-Files zu verwenden :shock:
Man muss doch mit Streams auch nicht gleich eine riesige, overengineerte Monster-Class programmieren. (Generics sind allerdings ganz nett in dem Fall, meine ich. Kann sein, dass die Syntax falsch ist, ich bin dank der Preise der neuen Delphi-Versionen leider nie in den Genuss gekommen.)

Delphi-Quellcode:
type
  TFortranStream = class
  protected
    FStream: TStream;
  public
    constructor Create(Stream: TStream);
    procedure Read<T>(var Rec: T);
    procedure Write<T>(const Rec: T);
  end;

implementation

{$R *.dfm}

constructor TFortranStream.Create(Stream: TStream);
begin
  FStream := Stream;
end;

procedure TFortranStream.Read<T>(var Rec: T);
var
  Len: Byte;
begin
  FStream.Read(@Len, sizeof(Byte));
  FStream.Read(@Rec, sizeof(T));
end;

procedure TFortranStream.Write<T>(const Rec: T);
var
  Len: Byte;
begin
  Len := sizeof(T);
  FStream.Write(@Len, sizeof(Len));
  FStream.Write(@Rec, sizeof(Rec));
  FStream.Write(@Len, sizeof(Len));
end;

type
  TFortranRecord = packed record
    A : Double;
    C,
    D : Integer;
    S : array[1..3] of AnsiChar;
  end;

procedure TForm1.Button1Click(Sender: TObject);
var
  F : File;
  FileStream: TFileStream;
  Fortran: TFortranStream;
  Rec: TFortranRecord;
begin
  FileStream := TFileStream.Create('Test.net');
  Fortran := TFortranStream.Create(FileStream);

  Rec.A := 1.0;
  Rec.C := 2;
  Rec.D := 2;
  Rec.S[1] := 'A';
  Rec.S[2] := 'B';
  Rec.S[3] := 'C';

  Fortran.Write<TFortranRecord>(Rec);
 
  Fortran.Free;
  FileStream.Free;
end;
(Fehlerbehandlung sollte da natürlich noch rein, hat dein Beispiel aber auch nicht).

Dejan Vu 19. Jul 2014 17:47

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Ich persönlich würde das über einen Stream lösen und jedes Feld einzeln einlesen. Das ist nur unwesentlich komplexer als ein Blockread mit Record, aber man sieht genau, was Sache ist. Letztendlich ist es Geschmackssache, denn wenn man den Record entsprechend deklariert, sieht man genauso, was Sache ist.

Mavarik 20. Jul 2014 12:47

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Namenloser (Beitrag 1266013)
2014 noch Leuten dazu zu raten, die alten Pascal-Files zu verwenden :shock:

Wieso "Shock"?

Ja natürlich Blockwrite... Wieso auch nicht.. Abgesehen davon das es Blockbezogen fast 100%ig das gleiche ist
(vielleicht ein klein wenig weniger overhead).

Ein Blockwrite ruft folgendes auf:

1. Function _blockwrite
2. BlockIO
3. IOProc (Kernel32 "Writefile");

"Dein Stream" ruft folgendes auf:

1. TStream.Write
2. Filewrite
3. WriteFile (Kernal32 "Writefile");

Lassen wir mal außer acht, dass der Blockwrite wenige Taktcycle weniger braucht.

Also macht "mein" alten Pascal-Files genau das gleiche... Noch Fragen?

Namenloser 20. Jul 2014 14:01

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Kannst du mit deinem Blockwrite/Blockread mal eben nachträglich auf eine andere Datenquelle umsteigen, z.B. einen MemoryStream?

Ich hab nicht grundsätzlich etwas gegen althergebrachte Methoden, aber Streams sind hier meiner Meinung nach in jeder Hinsicht überlegen. Man braucht ja nicht mal mehr Code – man kann mit Streams – wenn man will – genau so programmieren wie mit Pascal-Files. Aber man hat halt zusätzlich noch mehr Optionen.

Zitat:

Lassen wir mal außer acht, dass der Blockwrite wenige Taktcycle weniger braucht.
Ja, lassen wir besser wirklich außer acht. Ist schließlich absolut irrelevant, wenn die Methode 1ns länger braucht, wenn der Festplattenzugriff 10 000× so lange dauert.

Viel relevanter für die Performance ist, wie groß die Blöcke sind, die man einliest oder schreibt, und da würde ich wenn dann vermuten, dass das modernere API moderne Hardware besser auslastet.

Dejan Vu 20. Jul 2014 14:17

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Mavarik (Beitrag 1266096)
Also macht "mein" alten Pascal-Files genau das gleiche... Noch Fragen?

Ja. Wieso dann nicht gleich Maschinencode?. Ist doch auch genau das gleiche. ;-)

Mavarik 20. Jul 2014 16:38

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Zitat:

Zitat von Dejan Vu (Beitrag 1266105)
Zitat:

Zitat von Mavarik (Beitrag 1266096)
Also macht "mein" alten Pascal-Files genau das gleiche... Noch Fragen?

Ja. Wieso dann nicht gleich Maschinencode?. Ist doch auch genau das gleiche. ;-)

Da wo es noch Sinn macht... Warum nicht?

Zitat:

Zitat von Namenloser (Beitrag 1266104)
...und da würde ich wenn dann vermuten, dass das modernere API moderne Hardware besser auslastet.

Das ist ja der Witz... Geht ja beides auf die Kernel... Also genau die gleiche API.

Aber das hat jetzt echt nix mehr mit diesem Thread zu tun... Also würde sagen, wir beenden das hier...

p80286 21. Jul 2014 10:41

AW: Einlesen einer FORTRAN Binärdatei mit Delphi
 
Ein kleiner Nachsatz sei mir gestattet. Bis XP SP2..... (gefühlt) war das Block.. schneller als der Filestream (mit entsprechender Buffersize!) danach war es umgekehrt, darum hab ich längst alle Block.. durch TFilestream ersetzt.
Und "Monsterklassen" sind dafür auch nicht nötig.
Delphi-Quellcode:
fs.create(....,...);
repeat
  gelesen:=fs.read(buffer,zulesen);
until gelesen<zulesen;
fs.free;
Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:43 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz