Announcement

Collapse
No announcement yet.

Delphi 8 und File of

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Delphi 8 und File of

    Hallo
    ich muss unter Delphi 8 Dateien lesen und schreiben, welche früher mit File of deklariert wurden.
    Kann mir jemand anhand eines lauffähigen Beispieles zeigen wie das mit Delphi 8 funktioniert?
    <PRE>
    Z.B.
    Type abcRec = Record
    Feld1 : string;
    Feld2 : SmallInt;
    end;

    Var abcFile : File of abcRec;
    abc : abcRec;

    assign(abcFile, 'DataFile.dat');
    rewrite(abcFile);
    abc.Feld1 := 'Delphi';
    abc.Feld2 := 8;
    write(abcFile, abc);
    close(abcFile);

    seek(abcFile, 5);
    read(abcFile, abc);
    </PRE>

    Wie sieht der aequivalente Code in D8 aus?

    *** HERZLICHEN DANK für jede Hilfe ***
    Grüsse aus der Schweiz,
    Marco

  • #2
    Hallo,

    &gt;Var abcFile : File of abcRec;

    bereits beim Ausliefern der ersten Version der <i>Delphi.NET Preview</i> hat Borland in dem Papier <i>Delphi Language Changes</i> darauf hingewiesen, dass diese Technik unter .NET nicht mehr zur Verfügung steht. Im Detail liest sich das dann so:

    <i>"File of <type>: This construct cannot be implemented because the Delphi compiler cannot know the size of <type> on the target platform (e.g. a hand held device). The JIT compiler for the specific platform determines the size of intrinsic types."</i>

    &gt;Wie sieht der aequivalente Code in D8 aus?

    Entweder definiert man mühsam diese Struktur über das Attribut <i>[StructLayout(LayoutKind.Sequential)]</i> selbst (wobei das generelle Problem weiterhin relevant bleibt), oder man lagert diese "Low-Level-Funktion" in eine DLL aus, die mit einer früheren Delphi-Version compiliert wird. Delphi 8 bindet dann über P/Invoke nur diese DLL ein, um die Daten zu verarbeiten.

    &#10

    Comment


    • #3
      Vielen Dank, Herr Kosch, für Ihre schnelle Antwort.
      Dazu kann ich eigentlich nur sagen, unglaublich aber wahr. Es soll also in Zukunft nicht mehr möglich sein komplexe Datenstrukturen auf der Festplatte abzulegen. Und das ganze wird noch als Fortschritt angepriesen.
      <P>
      Wie soll man denn in Zukunft folgende Datenstruktur speichern:
      <P>
      <PRE>
      Type
      Denivel = Record
      Status : integer;
      Addition : integer;
      EZ : array [0..16,0..35] of integer;
      end;
      </PRE>
      Hat der Billi jetzt einfach entschieden, dass so etwas nicht mehr abzuspeichern ist.
      In meinen Applikationen wimmelt es von solchen Strukturen, welche ich in Dateien speichern muss.
      Natürlich ist es mittelfristig eine Lösung so etwas in einer DLL zu tun und mit einem alten Compiler zu compilieren.
      Aber in 5 Jahren ist alles Schrott was jetzt aktuell ist und dann stehe ich definitiv im Regen mit meinen Daten. Da kann ich mir ja schon mal überlegen, wann ich in Frühpension gehen soll und meine Anwender auf einen schleichenden Abgang vorbereiten.
      In Ihrem Buch "Crashkurs .NET für Delphianer" beschreiben Sie "FileStream" ".Create" usw. Ist hiermit auch keine Lösung möglich? Bin ich denn ein totaler Exot, dass ich solche Datenstrukturen speichern muss?
      <P>
      Hoch lebe der "Fortschritt".
      <P>
      Herzliche Grüsse
      Marco Verdier

      Comment


      • #4
        Hallo,

        &gt;Es soll also in Zukunft nicht mehr möglich sein komplexe Datenstrukturen auf der Festplatte abzulegen

        Nein - ganz im Gegenteil, unter .NET wird das sogar viel einfacher und es gibt mehrere Techniken dazu. Der Unterschied zu früher besteht darin, dass nun Objektinstanzen in der Datei gespeichert werden, aber keine feststehenden Datenblöcke, deren Teile später über <b>vorher festgelegte Offset-Adressen</b> extrahiert werden müssen. Es ist die Aufgabe dieser Objekte, sich selbst zur Laufzeit darum zu kümmern, dass auf jeder Hardware (Win32 oder Win64 oder PocketPC) die "wiederbelebte" Instanz ein funktionstüchtige Kopie des Originals ist.
        <br><br>
        &gt;In meinen Applikationen wimmelt es von solchen Strukturen, welche ich in Dateien speichern muss.
        <br><br>
        Hier gibt es die folgenden Alternativen, die ich nach der "Bequemlichkeit" (Einfachheit) geordnet absteigend sortiert aufliste: <br>
        a) DataSet-Instanz schreibt sich über den Aufruf einer Methode selbst in eine Datei <br>
        b) Konfigurationsklasse serialisiert sich selbst in eine Datei <br>
        c) Die <b>typsichere</b> Struktur wird als binärer Datenblock in eine Datei geschrieben.
        <br><br>
        Ein Beispiel für b) könnte so aussehen (ich habe dazu nur ein C#-Beispiel am Lager): Zuerst wird eine über das <b>Serializable</b>-Attribut gekennzeichnete eigene Klasse erstellt, welche die zu speichern Daten objektorientiert verpackt und über Objektfelder, Eigenschaften und Methoden veröffentlicht:
        <pre>
        <b>using</b> System;
        <br>
        <b>namespace</b> CSharpSerialization
        {
        <font color="#003399"><i>/// </i></font>
        <font color="#003399"><i>/// Summary description for Class1.</i></font>
        <font color="#003399"><i>/// </i></font>
        [Serializable()]
        <b>public</b> <b>class</b> OSDeveloperClass
        {
        <b>public</b> OSDeveloperClass()
        {
        <font color="#003399"><i>//</i></font>
        <font color="#003399"><i>// TODO: Add constructor logic here</i></font>
        <font color="#003399"><i>//</i></font>
        }
        <br>
        <b>public</b> OSDeveloperClass(<b>string</b> sName, <b>string</b> sVorname)
        {
        Name = sName;
        Vorname = sVorname;
        }
        <br>
        <b>public</b> <b>string</b> Name;
        <b>public</b> <b>string</b> Vorname;
        <b>public</b> DateTime Geburtstag;
        <br>
        <b>public</b> <b>string</b> GetDeveloperInfo()
        {
        <b>return</b> <b>String</b>.Format(<font color="#9933CC">&quot;Hallo, ich bin {0} {1} und wurde am {2} geboren.&quot;</font>,
        Vorname, Name, Geburtstag);
        }
        }
        }
        </pre>
        Das Programm muss dann nur über die Methoden <b>Serialize</b> und <b>Deserialize</b> dafür sorgen, dass die Objektinstanz ihren aktuellen Zustand in eine Datei schreibt und bei Bedarf erneut aus einer Datei wiederherstellt:
        <pre>
        <b>using</b> System.IO;
        <b>using</b> System.Runtime.Serialization.Formatters.Binary
        ...
        <br>
        <b>private</b> <b>void</b> Button1_Click(<b>object</b> sender, System.EventArgs e)
        {
        OSDeveloperClass aDev = <b>new</b> OSDeveloperClass(<font color="#9933CC">&quot;Kosch&quot;</font>, <font color="#9933CC">&quot;Andreas&quot;</font>);
        aDev.Geburtstag = Convert.ToDateTime(<font color="#9933CC">&quot;??.??.????&quot;</font>);
        FileStream aFS = <b>new</b> FileStream(@<font color="#9933CC">&quot;C:\Temp\SerObj2.dat&quot;</font>, FileMode.OpenOrCreate);
        BinaryFormatter aBF = <b>new</b> BinaryFormatter();
        aBF.Serialize(aFS, aDev);
        aFS.Close();
        }
        <br>
        <b>private</b> <b>void</b> Button2_Click(<b>object</b> sender, System.EventArgs e)
        {
        OSDeveloperClass aDev;
        FileStream aFS = <b>new</b> FileStream(@<font color="#9933CC">&quot;C:\Temp\SerObj2.dat&quot;</font>, FileMode.Open);
        BinaryFormatter aBF = <b>new</b> BinaryFormatter();
        aDev = (OSDeveloperClass)aBF.Deserialize(aFS);
        MessageBox.Show(aDev.GetDeveloperInfo());
        }
        </pre>

        Ein Beispiel für c) könnte so aussehen (ich habe dazu nur ein C#-Beispiel am Lager):
        <pre>
        <b>private</b> <b>const</b> <b>string</b> cFILENAME = @<font color="#9933CC">&quot;C:\Temp\Test.data&quot;</font>;
        <b>private</b> FileStream fs;
        <b>private</b> <b>int</b> iArraySize;
        <b>private</b> <b>double</b>[] da;
        <br>
        <b>public</b> <b>void</b> DoWrite()
        {
        fs = <b>new</b> FileStream(cFILENAME, FileMode.CreateNew);
        BinaryWriter w = <b>new</b> BinaryWriter(fs);
        <font color="#003399"><i>// Array-Größe an den Dateianfang schreiben</i></font>
        iArraySize = 10;
        w.Write((<b>int</b>)iArraySize);
        <font color="#003399"><i>// Daten anhängen</i></font>
        <b>for</b> (<b>int</b> i = 0; i &lt; iArraySize; i++)
        {
        w.Write((<b>double</b>)i);
        }
        w.Close();
        }
        <br>
        <b>public</b> <b>void</b> DoRead()
        {
        fs = <b>new</b> FileStream(cFILENAME, FileMode.Open, FileAccess.Read);
        BinaryReader r = <b>new</b> BinaryReader(fs);
        <font color="#003399"><i>// Größe des Array vom Dateianfang einlesen</i></font>
        iArraySize = r.ReadInt32();
        da = (<b>double</b>[])Array.CreateInstance(<b>typeof</b>(<b>double</b>), iArraySize);
        <font color="#003399"><i>// Nachfolgende Daten einlesen</i></font>
        <b>for</b> (<b>int</b> i = 0; i &lt; iArraySize; i++)
        {
        da[i] = r.ReadDouble();
        }
        r.Close();
        }
        <br>
        <b>private</b> <b>void</b> buttonWrite_Click(<b>object</b> sender, System.EventArgs e)
        {
        DoWrite();
        statusBar1.Text = <font color="#9933CC">&quot;Daten wurden geschrieben&quot;</font>;
        }
        <br>
        <b>private</b> <b>void</b> buttonRead_Click(<b>object</b> sender, System.EventArgs e)
        {
        DoRead();
        statusBar1.Text = <font color="#9933CC">&quot;Daten wurden gelesen&quot;</font>;
        <b>foreach</b> (<b>double</b> dValue <b>in</b> da)
        {
        listBox1.Items.Add(dValue.ToString());
        }
        }
        </pre>
        <br><br>
        Meine erste Antwort (Win32-DLL) bezog sich somit nur auf die Aufgabe, das "alte" Datendateien eingelesen werden müssen, die vorher von der Win32-Programmversion geschrieben wurden.
        <br><br>
        P.S: <br>
        Wenn wir ehrlich sind, liegen die Vorteile der neuen .NET-Regeln auf der Hand. Bisher gab es zum Beispiel beim Wechsel zu einer neueren Delphi-Version auch das Problem, dass durch die geänderte Speicherausrichtung von bestimmten Datentypen der alte binäre Dateiinhalt nicht mehr lesbar war. Über bestimmte Schlüsselwörter wie zum Beispiel <b>packed</b> konnten wir korrigierend eingreifen, aber das Problem (Risiko) war permanent da. Mit .NET entschärft sich die Situation, da es keinen "unbekannten binären Dateiinhalt" mehr gibt, sondern alle Informationen auf <b>typsicheren Weg</b> erreichbar sind

        Comment


        • #5
          Vielen Dank Herr Kosch für Ihre Mühe.
          Ich werde übungshalber versuchen das Beispiel mit SharpDevelop zum Laufen zu kriegen. Allerdings hilft mir das immer noch nicht meine bestehenden Daten in das neue Dateiformat zu konvertieren. Ich kann ja die alten Dateien nicht unter Delphi.NET öffnen und in die neue Datenstruktur übernehmen. Die Wegwerfmentalität hat bei Mikroschrott ganz böse zugeschlagen. Da muss ich Borland doch ein Kränzchen winden, dort ist man wenigstens bemüht mit der VCL.NET bestehenden Code teilweise zu retten. Na, ja und in einigen Jahren schmeissen wir wieder alles weg, wenn der gute Billi entschieden hat, dass jetzt wieder alles veraltet ist. Hoch lebe der Fortschritt.
          Freundliche Grüsse
          Marc

          Comment


          • #6
            Hallo,

            &gt;Allerdings hilft mir das immer noch nicht meine bestehenden Daten in das neue Dateiformat zu konvertieren.

            Für den Import von alten Daten muss die eigene Delphi 8-Anwendung <b>einmalig</b> auf eine über P/Invoke geschriebene Hilfs-DLL zugreifen, um die von der DLL erhaltenen "alten" Daten in das neue Format zu schreiben

            Comment

            Working...
            X