Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Array mit verschiedenen Records (https://www.delphipraxis.net/95275-array-mit-verschiedenen-records.html)

Scrutor 4. Jul 2007 13:39


Array mit verschiedenen Records
 
Hallo zusammen,

ich hab mal wieder ein Problemchen, bei dem ich nicht weiterkomme und ich denke mal hier wird mir die Frage schnell beantwortet.

Ich möchte eigentlich nur wissen, ob es möglich ist ein Array zu erstellen, in dem 5 verschiedene Records drin sind.

also ungefähr so:
Delphi-Quellcode:
type
  Rec1 = record
   a : char;
   b : char;
  end;

type
  Rec2 = record
   c: char;
   d: char;
  end;

...
 
RecArray:Array[0..4]of record;

RecArray[0]:=Rec1;
RecArray[1]:=Rec2;
...
RecArray[4]:=Rec5;
Geht das so wie ich mir das wünsche ? oder muss ich mir was anderes einfallen lassen ?

Bisher hab ich das nicht hinbekommen. :wall:

Vielen Dank für jede Hilfe.


mfg
Scrutor

sirius 4. Jul 2007 13:53

Re: Array mit verschiedenen Records
 
Geht, aber nur mit Tricks.
Einfacher machst du dir es hier mit Klassen.
Vielleicht nimmst du dann auch gleich eine TObjectList als Container statt eines Arrays.

Scrutor 4. Jul 2007 13:57

Re: Array mit verschiedenen Records
 
hmm,
hast du da irgendwo ein brauchbares Beispiel für ?

Hab mich mit Klassen und Containern noch nicht so befasst.


mfg
Scrutor

Der_Unwissende 4. Jul 2007 14:02

Re: Array mit verschiedenen Records
 
Hi,
so geht das nicht. Ein Array ist eine sehr einfache Art von Speicherstruktur, die nur dazu bestimmt ist einfach (und schnell) auf eine bestimmte (feste) Menge von gleichen Daten zugreifen zu können. Legst Du ein Array an, so wird einfach die Größe eines Elements mit der Anzahl der Elemente multitpliziert und der entsprechend Wert wird als Menge an Speicher alloziert. Anders gesagt, hast Du ein Array, dass aus 10 Integer Werten besteht (egal ob dynamisch oder statisch), dann wird hier einfach 10 * 4 Byte (sizeOf(Integer) = 4) alloziert. Nun merkt sich Delphi noch die Adresse des ersten Elements im Array. Möchtest Du nun auf das 7te Element zugreifen, so weiß Delphi hier, dass es einfach an 4 Byte an der Adresse (StartadresseDesArrays + 7 * 4) zugreifen muss.
Das ist gerade der Vorteil eines solchen Array, die Daten liegen alle am Stück im Speicher, da greifen einerseits Caching-Techniken recht gut und er wahlfreie Zugriff (Element an Stelle x) ist möglich.

Unterschiedliche Typen können eben genau diese Art von Zugriff nicht garantieren, das gilt auch für gleich große Elemente (z.B. Cardinal und Integer). Schließlich sind das unterschiedliche Typen, die könnten also (theoretisch) auch die Größe unabhängig voneinander ändern!

Was Du benutzen kannst ist immer etwas gleiches. Da gibt es schon mal die Möglichkeit, dass Du ein Array von Zeigern verwaltest und die speicherst. Die Records kannst Du dann (wenn Du die dyn. erzeugen willst) mit new erzeugen und die Adresse im Array speichern. Sind die Records statisch, musst Du darauf achten, dass die adresse nur lokal gültig ist, alles was Du in einer Methode als lokale Parameter deklarierst landet nur auf dem Stack und wird beim verlassen der Methode dort auch abgeräumt. Globale Variablen, Instanz- und Klassenvariablen, Instanzen von Klassen und eben mittels new erzeugte Typen unterliegen nicht der Einschränkung (Daten landen im Heap).

Das Problem dass Du beim arbeiten mit Zeigern hast (kannst hier auch auf eine TList statt einem Record of Pointerzurückgreifen) ist, dass Du nicht weißt was für einen Typ sich hinter dem Zeiger verbirgt. Der speichert nur eine Adresse, was sich an der Adresse befindet musst Du schon selbst wissen. Hier ist also die Frage, wie Du das ganze dann erkennen möchtest, eine Möglichkeit ist natürlich ein Record aus dem Typ und dem Zeiger.

Ansonsten kannst Du das ganze auch über Klassen realisieren. Die erben immer von der Basisklasse TObject. Details zu Klassen und OOP kannst Du in vielen Tutorials nachlesen, die meisten behandeln sicherlich auch Vererbung (und vergessen dafür häufiger mal die wichtigen Ideen der OOP).
Jedenfalls kannst Du jede Instanz einer Klasse immer wie eine TObject Instanz behandeln. Dabei siehst Du dann nur dass, was eben ein TObject anbietet (z.B. die Methode Free zum Freigeben der Instanz).
Hier kannst Du also auf ein Object of TObject oder eine TObjectList zurückgreifen. Ob eine Instanz nun vom Typ Klasse1 oder Klasse2 ist, kannst Du mittels dem Operator is (if Variable is TKlasse1 then ...) testen.

Gruß Der Unwissende

christian.noeding 4. Jul 2007 14:04

Re: Array mit verschiedenen Records
 
Hi - ich mache das immer so:

Delphi-Quellcode:
type
  Rec1 = record
   a : byte;
   b : string[255];
  end;

  Rec2 = record
   c: integer;
   d: word;
  end;

  RecComplete = record
   RecPart1 : Rec1;
   RecPart2 : Rec2;
  end;

RecArray : Array[0..4] of RecComplete;
Somit kann man in ein Array die unterschiedlichsten Sachen packen. :)

Der_Unwissende 4. Jul 2007 14:09

Re: Array mit verschiedenen Records
 
Zitat:

Zitat von christian.noeding
Hi - ich mache das immer so:

...

Somit kann man in ein Array die unterschiedlichsten Sachen packen. :)

Auf Kosten des Speicherverbrauchs. Du speicherst hier eben immer zwei Records in einem Datensatz. Je mehr unterschiedliche Records Du hast, desto schlimmer die Verschwendung!
Bei solchen unterschiedlichen Typen kannst Du dann auch ein varianten Record (einfach mal in die OH schauen) verwenden.

Scrutor 4. Jul 2007 14:10

Re: Array mit verschiedenen Records
 
hui, danke für die umfangreiche Info Der_Unwissende.
Nun weiss ich zumindest schonmal, dass die Lösung über Records in meinem Fall nicht (nie) funktionieren kann.

Ich werde mich dann nun mal den Klassen und Objecten widmen.


@christian.noeding
das wäre eine möglichkeit, aber ist für meinen Fall auch leider nicht brauchbar. trotzdem vielen dank.


ich beschreibe mal mein problem, vielleicht hat ja einer eine gute lösung:
Also, ich hab eine Text-Datei in der Datensätze gespeichert sind.
Diese muss ich laden.
Zeile 1 hat zum Beispiel 14 Datensätze, die bis auf den ersten Datensatz alle 8 Zeichen lang sind. Der erste Datensatz hat 10 Zeichen.
Nun kann es aber sein, dass bei einem alten Datenformat der erste Datensatz nur 9 Zeichen lang ist.
Also prüfe ich das Datei-Erstellungsdatum und entscheide danach, welchen Record ich benutze, um den Datensatz der ersten Zeile korrekt zu laden.

Datei von 2002 sieht so aus:
Delphi-Quellcode:
type
  TDaten_Zeile_1_altesFormat = record
    Auftr  : array[0..8]of char;  //Auftragsnummer
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
    LineFeed: array[0..1]of char;
  end;
Datei von 2004 sieht so aus:
Delphi-Quellcode:
type
  TDaten_Zeile_1_neuesFormat = record
    Auftr  : array[0..9]of char;  //Auftragsnummer
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
    LineFeed: array[0..1]of char;
  end;
so, davon gibt es also mehrere unterschiedliche Datensätze zu unterschiedlichen Datumsangaben.

Ich hab 5 Zeilen-Records und für jeden Zeilen Record kann es sein, dass ich 6 verschiedene Zeit-Records erstellen muss.
(Hab nämlich noch nicht alle Format unterschiede mir angeschaut)

ich hoffe jemand versteht mein Porblem wenigstens ansatzweise :)

sirius 4. Jul 2007 14:26

Re: Array mit verschiedenen Records
 
Iim einfachsten Fall:
Delphi-Quellcode:
type TClass1=class
       x,y:integer;
end;

type TClass2=class
       b:string;
       c:char;
end;

...
var Liste:TObjectList
    Class1:Tclass1;
    Class2:Tclass2;

//irgendwo Liste erstellen
Liste:=Tobjectlist.create;
Liste.ownsobjects:=true; //damit verwaltet die Liste ihre Elemente selber

//Object einfügen
Class1:=Tclass1.create;
Liste.add(Class1);
Class1.x:=5;

//usw..
Class2:=Tclass2.create;
...


//Zugriff über
list.Items[0]
list.items[1]
//also
Class1:=list.items[0];
ergebnis:=Class1.x
//oder
ergebnis:=TClass1(list.items[0]).x;
Soweit erstmal.
Hier geht aber noch viel mehr.

marabu 4. Jul 2007 16:28

Re: Array mit verschiedenen Records
 
Hallo Scrutor,

bei Textdateien gibt es zwei Basis-Formate: Fixed-Field und Comma-Separated. Die Bezeichnungen sagen aus, dass im ersten Fall die einzelnen Felder über ihren Offset und im letzteren Fall durch Abzählen der Trennzeichen lokalisiert werden. Deine Textdaten gehören in die erste Kategorie.

Für deine beiden Datensatztypen kommt man leicht zu folgenden Strukturen:

Delphi-Quellcode:
type
  TAuftragDaten = record
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
  end;

  TAuftrag2002 = record
    Nr : array[0..8]of char;  //Auftragsnummer
    Spec: TAuftragDaten;
  end;

  TAuftrag2004 = record
    Nr : array[0..9]of char;  //Auftragsnummer
    Spec: TAuftragDaten;
  end;
Einlesen kannst du diese Daten wahlweise über die alten Pascal Standardroutinen ReadLn (ohne vorherige Kenntnis der Satzlänge) und BlockRead (mit vorheriger Kenntnis der Satzlänge) oder über einen FileStream.

Wenn nur diese beiden Datensatztypen existieren, dann kannst du auch einfach den größeren Typ verwenden und beim Einlesen die erste Stelle mit einem Leerzeichen oder einer Null initialisieren, wenn die kurzen Sätze verarbeitet werden.

Grüße vom marabu

Scrutor 5. Jul 2007 06:57

Re: Array mit verschiedenen Records
 
Hallo marabu,

diese Lösung hört sich sehr gut an.
Da ja mehr als nur diese 2 datensätze existieren, ist diese Möglichkeit brauchbar.

Ich hab das mal wie folgt angefangen:
Delphi-Quellcode:
type
  TZeile_1 = record
    Dum1    : array[0..7]of char;  //Dummy
    ProgNr : array[0..7]of char;  //Programmnummer
    ZeichNr : array[0..7]of char;  //Zeichnungsnummer
    LineNr : array[0..7]of char;  //Lineelement
    IdBohr : array[0..7]of char;  //Ident Bohren
    IdVorr : array[0..7]of char;  //Ident Vorrichtung
    Dum2    : array[0..7]of char;  //Dummy
    AVO    : array[0..7]of char;  //AVO
    Mach   : array[0..7]of char;  //Maschine
    Durchm : array[0..7]of char;  //Raddurchmesser
    AusWink : array[0..7]of char;  //Austrittswinkel
    AnzScha : array[0..7]of char;  //Anzahl Schaufeln
    SchaHohe: array[0..7]of char;  //Schaufelhöhe
    LineFeed: array[0..1]of char;
  end;

type
  TZeile_1_vor04 = record
    Auftr  : array[0..8]of char;  //Auftragsnummer
    Spec   : TZeile_1;
  end;

type
  TZeile_1_nach04 = record
    Auftr  : array[0..9]of char;  //Auftragsnummer
    Spec   : TZeile_1;
  end;

type
  TZeile_2 = record
    MesDurch: array[0..8]of char;  
    EinDur : array[0..7]of char;  
    FLAS   : array[0..4]of char;  
    Wkstoff : array[0..7]of char;  
    Stueck : array[0..7]of char;  
    Dum4    : array[0..7]of char;  
  end;

type
  TZeile_2_vor03 = record
    Spec   : TZeile_2;
    SchaHoSi: array[0..7]of char;  
    ZwShaSi : array[0..7]of char;  
    LineFeed: array[0..1]of char;
  end;

type
  TZeile_2_nach03 = record
    Spec   : TZeile_2;
    SchaHoSi: array[0..7]of char;  
    ZwShaSi : array[0..7]of char;  
    MaxType : array[0..7]of char;  
    LineFeed: array[0..1]of char;
  end;
so, nun lese ich aber ja in einer procedure die Datei mit Filestream aus und übergebe die ausgelesenen records an eine weitere procedure, die die einzelenen Daten dann in Editfelder, etc. einträgt.

wie deklariere ich in der ersten procedure am besten die verschiedenen records ?
und wie übergebe ich die an die nächste procedure ?
alle global deklarieren ?


mfg
Scrutor

SirThornberry 5. Jul 2007 07:24

Re: Array mit verschiedenen Records
 
so gehts:
Delphi-Quellcode:
TRec1 = record
   a : char;
   b : char;
end;

TRec2 = record
  c: char;
  d: char;
end;

TRec1or2 = record
  case Bool of
    True: (Variante1: Rec1);
    False: (Variante2: Rec2);
end;

RecArray:Array[0..4]of record;
Dabei ist das Array-Elemente so groß wie der größte Recordtyp - Wenn also TRec1 und TRec2 gleich groß sind wird nicht mehr speicher als normal verbraucht.

Scrutor 5. Jul 2007 09:06

Re: Array mit verschiedenen Records
 
Ich hänge nun an folgendem Problem fest:

Delphi-Quellcode:
type
  TDataArray = array[0..4] of variant;

var
  DataArray : TDataArray; // ???

...

  Format:=0;
  CreateDate:=StrToDate(FormatDateTime('dd.mm.yy',GetFileModifyDate(Fread)));
  if CreateDate<StrTodate('22.01.04') then Format:=1;
  if CreateDate<StrTodate('23.07.03') then Format:=2;
  if CreateDate<StrTodate('21.02.02') then Format:=3;
  if CreateDate<StrTodate('27.04.01') then Format:=4;
  if CreateDate<StrTodate('31.10.00') then Format:=5;
  case Format of
    0: begin
         DataArray[0]:=TZeile_1_nach04;
         DataArray[1]:=TZeile_2_nach03;
         ...
         DataArray[4]:=TZeile_5_nach04;
       end;
    1: begin
         DataArray[0]:=TZeile_1_vor04;
         DataArray[1]:=TZeile_2_nach03;
       end;
    2: begin
        DataArray[0]:=TZeile_1_vor04;
        DataArray[1]:=TZeile_2_vor03;    
       end
    else
     begin
       ShowMessage('Format wird noch nicht unterstützt.');
       exit;
     end;
  end;

  fStream:=TMemoryStream.Create;
  try
    fStream.LoadFromFile(Fread);
    fStream.ReadBuffer(DataArray[0],SizeOf(DataArray[0]));
    fStream.ReadBuffer(DataArray[1],SizeOf(DataArray[1]));
    fStream.ReadBuffer(DataArray[2],SizeOf(DataArray[2]));
    fStream.ReadBuffer(DataArray[3],SizeOf(DataArray[3]));
    fStream.ReadBuffer(DataArray[4],SizeOf(DataArray[4]));
  finally
    fStream.Free;
  end;
ich weiss nicht, wie ich anders den Datensatz in das array bekomme, um den richtigen datensatz auslesen zu können
:gruebel: :cry: :wall: :freak:

sirius 5. Jul 2007 09:17

Re: Array mit verschiedenen Records
 
Dein Sizeof(DataAray[x]) dürfte unabhängig von x immer 16 liefern. so groß ist eben ein Variant. Und in den 16 Bytes des Variant steht dann der Typ mit dem das Variant derzeit belegt ist und je nach Typ die entspr Daten.

:gruebel: Kann man ein Variant eigentlich mit einem Record direkt füllen?

Edit: Hier ist ja noch einiges anderes schief. :warn: DataArray[0]:=TZeile_1_nach04;
Und Recods kann man tatsächlich nicht einem variant zuordnen (Delphi 7).

Den Ansatz solltest du besser wegwerfen.

Scrutor 5. Jul 2007 09:23

Re: Array mit verschiedenen Records
 
ich bin grad dabei es mit einem array of pointer zu probieren. (learning by doing :D )

mit sizeof ist mir grad auch schon aufgefallen.

ganz schön verzwickt der scheiss.


edit: der erste ansatz ist schon weg :D

Billa 5. Jul 2007 10:13

Re: Array mit verschiedenen Records
 
...also habe ich das richtig verstanden: das Format hängt nur vom Datum der Datei ab?

Scrutor 5. Jul 2007 10:26

Re: Array mit verschiedenen Records
 
richtig Billa,
anhand des erstellungsdatums wähle ich das dafür notwendige format.

nur ich verzweifel grad an der zuweisung


mfg
Scrutor

Billa 5. Jul 2007 10:30

Re: Array mit verschiedenen Records
 
Warum liest Du nicht - abhängig vom Datum - SizeOf(xxx) Zeichen in einen String, fügst bei den kleineren(älteren?) Sätzen ans Ende des Feldes von AuftrNr mit insert ein Leerzeichen (oder bei numerischen Auftragsnummer am Anfang eine führende Null) ein und benutzt nur EINE Datenstruktur? Sprich: anschließend den String per Typecast oder Move(src,dest,cnt) in die Struktur kopieren Ok...ist nicht gerade schnell, aber das sieht nach einem einmaligen Import aus. Da ist "Speed" wohl nicht so entscheidend.

Scrutor 5. Jul 2007 10:43

Re: Array mit verschiedenen Records
 
@Billa
weil das doch zu aufwendig wäre meiner meinung nach.
die unterschiede in den formaten sind auch mal mitten in einem record, also nicht immer am ende oder am anfang.
und da dann immer die richtige stelle zu finden ist bestimmt möglich, aber zu umständlich find ich.

ich hab 6 Zeitabfragen und 5 Zeilen, die je nach datum anders aussehen (können).
Delphi-Quellcode:
Zeile1
  Zeile1_1 //Format 1, etc.
  Zeile1_2
  Zeile1_3
  Zeile1_4
  Zeile1_5
  Zeile1_6
Zeile2
  Zeile2_1
  Zeile2_2
  Zeile2_3
  Zeile2_4
  Zeile2_5
  Zeile2_6

Billa 5. Jul 2007 10:48

Re: Array mit verschiedenen Records
 
..ich finde es relativ einfach je nach Struktur Leerzeichen einzufügen... sowas lässt sich sogar prima über eine Steuerdatei mit der jeweiligen Satzstruktur steuern. Damit ist man dann auch für weitere Formate offen, ohne die "hart" codieren zu müssen. Ändern der Steuerdatei und NICHT neu compilieren. D.h. das funktioniert dann auch beim Kunden oder wenn der Programmierer mal NICHT da ist, Delphi nicht zur Verfügung steht oder, oder, oder.... Aber ok. Ist das ganze denn jetzt ein einmaliger Vorgang?

Scrutor 5. Jul 2007 10:57

Re: Array mit verschiedenen Records
 
ich programmiere einfach nur ein altes Fortran-Programm in Delphi neu.
und diese Dateiformate sind halt historisch gewachsen.
ich will halt nur, dass man die alten Datensätze auch noch in meinem neuen Programm weiterhin benutzen kann (zumindest laden).
Deswegen ja die Datumsabfrage.

alle datensätze die nach 2004 erstellt wurden, ändern sich vorerst nicht und wenn dann mach ich das dateiformat eh komplett neu.
also ist das mit einer steuerdatei hinfällig.
und da der kunde nur aus 2 leuten besteht (ich bin einer von den 2 :) ), ist es auch nicht schlimm, wenn der programmierer mal pennt :D :roll:

ich hätte am liebsten nur die aktuellste datei-struktur genommen, aber dann hätte man alle alten sachen (wenn sie denn wiederkommen) komplett neu oder erst mit dem alten Fortran-Programm machen müssen.

also es ist ein einmaliger vorgang



mfg
Scrutor

Billa 5. Jul 2007 11:13

Re: Array mit verschiedenen Records
 
uppsss.. laufen denn die Fortran-Programme parallel weiter? In solchen Umgebungen gibt es i.d.R. noch mehr "Dinosaurier", deshalb könnte eine solche Routine mehrfach verwendet werden. In meinem Job haben wir es aus historischen Gründen mit dBase und Dataease-Dateien aus mehreren Projekten zu tun. (eigene und von Kunden) Also haben wir uns die Mühe EINMAL gemacht und einen Konverter nach SQL geschrieben. Der wird über Textdateien gesteuert. Das Ding taugte bisher für ca ein Dutzend Migrationsprojekte. Aber das scheint ein anderer Fall zu sein.

Wenn Du sowieso später neue Datenstrukturen entwickeln willst, lohnt sich der Aufwand vielleicht wirklich nicht. Ich ziehe es allerdings vor, im Klartext lesbare Steuerdateien zu verwenden, statt verschachtelte Klassen und Objekte. Nach spätestens einem halben Jahr taucht dann doch ein Fall auf, wo das ohne Zweifel elegante Konstrukt dann doch nicht mehr passt. Ich will Dich nicht überreden, aber Wiederverwendbarkeit ist ein n icht zu unterschätzender Kosten- und Zeitvorteil. Viel Erfolg jedenfalls. An dieser Stelle klinke ich mich aus. ...muß ja schließlich ein bißchen was arbeiten....

Apollonius 5. Jul 2007 11:41

Re: Array mit verschiedenen Records
 
Was haltet ihr von einem array of pointer? Also ungefähr so:
Delphi-Quellcode:
type
TRec1=record //alter Record
//
end;
PRec1=^TRec1;
TRec2=record //neuer Record;
//
end;
PRec2=^TRec2;
var alteversion: boolean; Daten:array[0..9] of pointer;//Größe des Arrays natürlich beliebig
    groesse:integer; //abhängig von alteVersion auf sizeof(TRec1) oder sizeof(TRec2) gesetzt

//Jetzt erstmal alteVersion und Groesse richtig setzen. Dann für jedes Element von Daten mit getmem genau so viel Speicher allozieren, wie für den benutzten Record gebraucht wird. Beim auslesen dann in den entsprechenden Zeigertyp casten

for i:=0 to 9 do
  getmem(array[i],groesse)
//Jetzt einlesen
meinStream.read(array[i]^,groesse);

//Verwendung:
if alteVersion then
  begin
    PRec1(Daten[0])^ //Und irgendwas damit machen
  end
else
  begin
    PRec2(Daten[0])^ //Und irgendwas damit machen
  end;

//Am Ende natürlich freemem nicht vergessen
Ist natürlich relativ viel Code, da du oft alteVersion abfragen musst, aber du kannst dir ja Funktionen bauen, die das automatisieren.

Scrutor 5. Jul 2007 12:30

Re: Array mit verschiedenen Records
 
so, ich hab mir nun was ganz anderes einfallen lassen, was meiner meinung nach auch am einfachsten ist.

ich habe nun 6 verschiedene records, also für jeden Datumsfall ein extra record.

nur jetzt steh ich wieder auf dem schlauch, wie kann ich die denn jetzt zuordnen ?


Delphi-Quellcode:
...
var
  Data0:TDaten_0;
  Data1:TDaten_1;
  Data2:TDaten_2;
  Data3:TDaten_3;
  Data4:TDaten_4;
  Data5:TDaten_5;

...

  Format:=0;
  CreateDate:=StrToDate(FormatDateTime('dd.mm.yy',GetFileModifyDate(Fread)));
  if CreateDate<StrTodate('22.01.04') then Format:=1;
  if CreateDate<StrTodate('23.07.03') then Format:=2;
  if CreateDate<StrTodate('21.02.02') then Format:=3;
  if CreateDate<StrTodate('27.04.01') then Format:=4;
  if CreateDate<StrTodate('31.10.00') then Format:=5;
  case Format of //format wählen
    0: begin
         //benutze "Data0" record
         DataArray[0]:=Data0;
         groesse[0]:=Sizeof(TDaten_0);
       end;
    1: begin
         //benutze "Data1" record
       end
    else
     begin
       ShowMessage('Format wird noch nicht unterstützt.');
       exit;
     end;
  end;

  fStream:=TMemoryStream.Create;
  try
    fStream.LoadFromFile(Fread);

    fStream.ReadBuffer(DataArray[0],sizeof(groesse[0]));
    {fStream.ReadBuffer(DataZ2,SizeOf(DataZ2));
    fStream.ReadBuffer(DataZ3,SizeOf(DataZ3));
    fStream.ReadBuffer(DataZ4,SizeOf(DataZ4));}

      //  fStream.ReadBuffer(DataZ5,SizeOf(DataZ5));
  finally
    fStream.Free;
  end;
 
  EditIdVor.Text:=trim(DataArray[0].IdVorr);

Scrutor 6. Jul 2007 08:02

Re: Array mit verschiedenen Records
 
es ist zum verzweifeln, ich komme einfach nicht weiter. :wall:

ist es vielleicht möglich eine Variable dynamisch zuzuordnen ?

also beispielsweise im Prinzip so:
Delphi-Quellcode:
var
   Data : ???;
begin
  case Format of
   0: Data:=TDaten_0;
   1: Data:=TDaten_1;
  end;
end;
ich weiss einfach nicht wie ich das machen soll


mfg
Scrutor

sirius 6. Jul 2007 08:17

Re: Array mit verschiedenen Records
 
Ja, du kannst es dynamisch zuordnen. Da musst du den Speicher selbst verwalten.

Prinzip:
Delphi-Quellcode:
type TDaten1=record
...

var typ:array of byte;
    DatenArray:Array of pointer;


procedure readversion1(const Stream:Tstream;pos:integer);
var Daten1:^TDaten1;
begin
  new(Daten1) //Speicher reservieren
  stream.read(Daten1^,sizeof(TDaten1);
 
  Datenarray[pos]:=Daten1;
  typ[pos]:=1; //du musst dir ja merken, an welcher Stelle du welchen Typ von record hast
end;

procedure readversion2.....

//zugriff
  Daten1:=Datenarray[pos];
  showmessage(Daten1^.xyz);




//am Ende speicher mit dispose freigeben
  case typ[pos] of
    1: begin
         Daten1:=Datenarray[pos];
         dispose(Daten1);
...
Anmerkung du kannst dir auch gleich einen Typ machen


So, ich muss erstmal los....

Scrutor 6. Jul 2007 09:19

Re: Array mit verschiedenen Records
 
danke sirius,

aber irgendwie versteh ich nicht so ganz was du da machst bzw. vorhast.

wieso "procedure readversion2....."

blick da nicht so durch .



mfg
Scrutor

hoika 6. Jul 2007 09:36

Re: Array mit verschiedenen Records
 
Hallo,

ich denke, du gehst falsch heran.
Das einfachste ist doch, wenn du die alten Daten in das neue Format konvertierst
und dann nur mit dem neuen arbeitest.

Ausnahme: Das alte Fortran-Programm läuft immer noch.

In diesem Fall würde ich auf jeden Fall auf Klassen umsteigen.
Trenne das Lesen der Daten von deinen internen Datenstrukturen.

Delphi-Quellcode:
type
  TDataItem = class
    public
      iVersion  : Integer; // 1-6 ?
      sProjectNo : String;
  end;
Zum Lesen benutzt du deine Records,
schreibst die Daten aber dann in das TDataItem rein

Jetzt gibt es nur noch einen Unterschied beim Lesen und Schreiben.
In deinem Code benutzt du nur das TDataItem.


Heiko

Scrutor 6. Jul 2007 09:42

Re: Array mit verschiedenen Records
 
Hallo hoika,

also das alte Fortran-Programm ist natürlich noch im Dienst und soll auch vorerst parallel weiterlaufen können,
deswegen mach ich mir ja diese Arbeit.

Mit den Klassen hab ich das noch nicht geschnallt. Bin erstmal grad nun noch dran mit Pointern zu arbeiten.

es muss doch irgendwie auch so gehen



mfg
Scrutor

Apollonius 6. Jul 2007 10:14

Re: Array mit verschiedenen Records
 
Ich und Sirius meinten prinzipiell das selbe. Die unterschiedlichen Readversions bei Sirius gibt es, damit du in einem Fall readversion1 aufrufst und im anderen Fall readversion2. Sirius kapselt das, was ich mittendrin gemacht habe. Du machst also von deiner Version abhängig, welche Funktion du aufrufst.

Scrutor 6. Jul 2007 10:19

Re: Array mit verschiedenen Records
 
ich bekomme aber nichts von alledem an meinem beispiel zum laufen.

weder deinen ansatz noch den von sirius.

entweder klappt das nicht, oder ich hab einfach nur irgendwo nen denkfehler

Sidorion 6. Jul 2007 11:28

Re: Array mit verschiedenen Records
 
Mein Vorschlag wäre:
Delphi-Quellcode:
Type
  TRecordKind=(rkGanzAlt, rkNichtsoAlt, rkNeu, ...);
  TMyRecord= Record
   Kind: TRecordKind;
   case TRecordKind of
     rkGanzAlt:
     // hier alle Member vom alten typ
     rkNichtsoAlt:
     // hier alle Member vom alten typ
     rkNeu:
     // hier alle Member vom alten typ
     ..:
     // hier alle Member vom alten typ
   end;
  end;
Jetzt kannst Du Dir ein Array von diesen Records erstellen und abhängig vom Dateidatum den RecordKind ermitteln. Diesen schreibst Du mit in den Record und kannst dann überall im Programm wissen, welcher art dieser Record ist und dementsprechend zugreifen.
Zu dem Stream lesen: Erstelle Dir für jeden RecordKind eine Konstante, die die jeweilige Gesaamtlänge beinhaltet, dann kannst Du immer soviele Bytes einlesen.

Apollonius 6. Jul 2007 11:39

Re: Array mit verschiedenen Records
 
Dann aber im richtigen Stil für variante records (kein end nach dem case!):
Delphi-Quellcode:
TMyRecord= Record
   case Kind:TRecordKind of
     rkGanzAlt:
     // hier alle Member vom alten typ
     rkNichtsoAlt:
     // hier alle Member vom alten typ
     rkNeu:
     // hier alle Member vom alten typ
     ..:
     // hier alle Member vom alten typ
   end;

Scrutor 6. Jul 2007 11:39

Re: Array mit verschiedenen Records
 
Das einlesen ist nicht das Problem.
das erstellen des richtigen records nun auch nicht mehr.

nur wie sag ich der Variablen Data, dass sie mal der eine record ist und mal der andere ?

Prinzip:
Delphi-Quellcode:
var
   Data : ???;
begin
  case Format of
   0: Data:=TDaten_0;
   1: Data:=TDaten_1;
  end;
end;
edit: ich find es leichter und einfacher 6 records zu erstellen, als mit den variant recordds rumzukaspern.
die 6 records sind ja schon erstellt und fertig, nur die zuweisuzng und auslesen und einem editfeld zuweisen klappt nicht

hoika 6. Jul 2007 12:00

Re: Array mit verschiedenen Records
 
Hallo,

so wie du das schreiben willst, musst du für jede der 6 Versionen
eine eigene Variable mitführen.

Die 6 Records unterscheiden sich noch mal wodurch ?
Durch bestimmte String-Längen ?

Wenn ja, benutze für das Lesen/Schreiben deine 6 verschiedenen Records,
aber in allen anderen Routionen genau einen Record
(nur String als Type, nicht array[0..] of Char).

Wenn du unbedingt eine 6 records haben willst,
dann könntest du auch so vorgehen
Delphi-Quellcode:
type
  TRec1 = record
    // Daten
  end;
type
  TRec2 = record
    // Daten
  end;

..
type
  TRec6 = record
    // Daten
  end;

type
  TRecAllData : record
    iVersion: Integer; //1-6
    Rec1: TRec1;
    Rec2: TRec2;
    ..
    Rec6: TRec6;
  end;
Sie umständlich aus, ist es auch ...


Heiko

Scrutor 6. Jul 2007 12:04

Re: Array mit verschiedenen Records
 
naja, ich mache dann jetzt zu den 6 verschiedenen records noch 6 proceduren, die die datei dann mit dem richtigen record auslesen.
find ich zwar unschön und irgendwie umständlich, aber es geht wohl nicht anders, bzw. ich bekomme es nicht anders hin.

vielen dank trotzdem an alle hier für ihre bemühungen


Edit: so, mit den 6 records und 6 proceduren funktioniert es nun einwandfrei.


mfg
Scrutor

Ghostwalker 6. Jul 2007 16:08

Re: Array mit verschiedenen Records
 
Es reicht eigentlich 1 Routine zum lesen:

Delphi-Quellcode:
   procedure ReadFromStream(Data:Pointer;Datasize:Integer);
   begin
     Stream.Read(data^,datasize);
   end;

Je nach Typ mußt du natürlich entsprechend die Daten übergeben.


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:19 Uhr.

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