Autor Beitrag
maximus
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Do 13.11.03 01:49 
Hallo Unit sektion!


Mit der klasse TmxCollection ist es möglich serielle datenstrukturen, jeglicher typen und komplexität, zu streamen. Hierzu wird das Delphi component streaming system benutzt, kombiniert mit einem kleinen fake-trick. Dabei kann im binär format, als auch im text-dfm format gespeichert werden!

Dazu stehen folgende methoden zur verfügung:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
procedure LoadFromStream(aStream: TStream; isBinary: Boolean);
procedure LoadFromFile(FileName: String; isBinary: Boolean);

procedure SaveToStream(aStream: TStream; asBinary: Boolean);
procedure SaveToFile(FileName: String; asBinary: Boolean);


Bei verwendung dieser methoden werden alle Items, einer selbst abgeleiteten TCollectionItem klasse automatisch gespeichert oder geladen. Beim laden werden die item automatisch instanziert und deren published properties gesetzt. Beim speichern werden alle published properties verwendet, bei denen der wert vom default wert abweicht - bzw. nicht stored false ist - bzw. die nicht readOnly sind.

Diese beispiel klasse...

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
  TmxCustomItem = class(TCollectionItem)
  private
    ...
  published            
    property aBoolean : boolean read FaBoolean  write FaBoolean;
    property anInteger : integer read FanInteger  write FanInteger;
    property anotherInteger : integer read FanotherInteger  write FanotherInteger default 0;     
    property anExtended : Extended read FanExtended  write FanExtended; 
    property anEnum :  TFilerFlag read FanEnum  write FanEnum; 
    property aSet : TFilerFlags read FaSet  write FaSet;     
    property aString : string read FaString write FaString stored false;      
  end;


...produziert folgenden output:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
object mxCustomItems: TmxCollection
  Items = <
    item
      aBoolean = True
      anInteger = 5
      anotherInteger = 666
      anExtended = 1.234560000000000000
      anEnum = ffChildPos
      aSet = [ffChildPos,ffInline]
    end
    ...
    ...
    ...
    item
      aBoolean = False
      anInteger = 3
      anExtended = 111.000000000000000000
      anEnum = ffInline
      aSet = []
    end>
end



Das soll aber nicht heissen, dass man keine normalen properties oder binäre daten speichern kann! Denn zu diesem zweck kann, in der item-klasse, die methode DefineProperties überschrieben werden. Mehr dazu in der Delphi hilfe oder in meinem advanced sample.

Desweiteren werden auch object properties, die von TPersistent abgeleitet sind, mit qualifizierer (.) geschrieben. und TBitmaps sind auch kein problem, dadurch werden die text-DFMs jedoch sehr gross, deshalb sollte bei grösseren bildern asBinary true benutzt werden.

Beim instanzieren der Collection wird die eigene item klasse übergeben, wie üblich:
ausblenden Delphi-Quelltext
1:
MyCollection := TmxCollection.Create(TmxCustomItem);					


Die benutzung ist sehr einfach und sollte selbsterklärend sein:

ausblenden Delphi-Quelltext
1:
2:
3:
MyCollection.SaveToFile('c:/data.dfm',false);// als text! für binär -> true
 ...
MyCollection.LoadFromFile('c:/data.dfm',false);

Alles weitere in der Delphi hilfe unter TCollection.

Ein erweitertest testprogramm findet ihr hier (7 kb). Die unit ist auch dabei.


Achtung! Die unit ist veraltet -> vorerst gibt es weiter unten einen link auf die dpCollection unit! werde das hier demnächst updaten.

Hier die unit:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
{-----------------------------------------------------------------------------
 Unit Name : mxCollection
 Author    : Max hub (maximov)
 License   : OPEN - WITHOUT WARRANTY.
             Do not remove this header! but updating the history is desired.
             
             please send fixes, samples, extensions or bubclasses to
             mx@eyer-systems.de                                                      
 
 Purpose   : Colletion based object streaming persistence! Saving and loading of
             complex serial data formats - any type of any complexity ;)
 History   : 02.11.2003 - version 0.42
-----------------------------------------------------------------------------}
    


unit mxCollection;

interface

uses classes, SysUtils;

type

  TmxCollectionError = class(Exception);
  TmxCollectionSigWrong = class(TmxCollectionError);


  TmxCollection = class(TCollection) // a Collection class combined with streaming caps
  private
    FIgnoreSignature: boolean;
  protected
  public         
    function GetFormatSignature: Stringvirtual;

    procedure LoadFromFile(FileName: String; isBinary: Boolean); // we know it...we love it!
    procedure LoadFromStream(aStream: TStream; isBinary: Boolean);
    procedure SaveToFile(FileName: String; asBinary: Boolean);
    procedure SaveToStream(aStream: TStream; asBinary: Boolean);

    property IgnoreSignature: boolean  read FIgnoreSignature write FIgnoreSignature;
  published 

  end;
  

implementation


function TmxCollection.GetFormatSignature: String;
begin                            
  Result := copy(ItemClass.ClassName,2,255) +'s';  // no special chars allowed !!!
end;


procedure TmxCollection.LoadFromFile(FileName: String; isBinary: Boolean);
var fileStream : TFileStream;
begin
  fileStream := TFileStream.Create(fileName, $0); //fmOpenRead
  try
    LoadFromStream(fileStream, isBinary);
  finally
    fileStream.free;
  end;
end;


procedure TmxCollection.LoadFromStream(aStream: TStream; isBinary: Boolean);
var Reader       : TReader;
    MemoryStream : TMemoryStream;
    format       : TStreamOriginalFormat;
    formatSig    : string;
begin
  MemoryStream := TMemoryStream.Create;                // work stream
  try    
    if not isBinary then
    begin
      format := sofBinary;                             // set destination format
      ObjectTextToBinary(aStream,MemoryStream,format); // convert DFM-text to binary
    end else MemoryStream.LoadFromStream(aStream);     // copy to work stream
    MemoryStream.Position := 0;                        // make ready to read
    Reader := TReader.Create(MemoryStream,2048);       // create the reader 
    try
      try      
        Reader.ReadSignature;                          // DFM signatur
        
        { Fake a host object for the 'items' because a DFM 
          is'nt complete without a root 'OBJECT' container! }

        
        // read className                        
        Reader.ReadStr;   
        // read your sig          
        formatSig := Reader.ReadStr; 

        if not FIgnoreSignature and (formatSig <> GetFormatSignature) then 
          raise TmxCollectionSigWrong.Create('Signatures differs from the expected one!');
          
        // read 'Items' property name  
        Reader.ReadStr; 
        // read the prop/value delimiter                      
        Reader.ReadValue;        
        // !!! read all the collection items and subobjects !!!     
        Reader.ReadCollection(self);  

        Reader.ReadListEnd;                             
        Reader.ReadListEnd;           // ...The 'End'...       
      except
        on TmxCollectionSigWrong do;
        else raise TmxCollectionError.Create('ERROR: loading collection!');
      end;  
    finally
      Reader.Free;
    end;
  finally
    MemoryStream.Free;
  end;
end;


procedure TmxCollection.SaveToFile(FileName: String; asBinary: Boolean);
var fileStream : TFileStream;
begin
  fileStream := TFileStream.Create(fileName, $FFFF); //fmCreate
  try
    SaveToStream(fileStream, asBinary);
  finally
    fileStream.free;
  end;
end;


procedure TmxCollection.SaveToStream(aStream: TStream; asBinary: Boolean);
var Writer       : TWriter;
    MemoryStream : TMemoryStream;
    format       : TStreamOriginalFormat;      
begin                                                 
  // work stream
  MemoryStream := TMemoryStream.Create;                
  try                                                  
    // writer core
    Writer := TWriter.Create(MemoryStream,2048);       
    try
      try   
        // DFM sig
        Writer.WriteSignature;   
                              
        // fake the header ;)
        
        Writer.WriteStr(ClassName);                    
        // gives your format a ID - override 'GetFormatSignature' to change 
        Writer.WriteStr(GetFormatSignature);    
        // fake the 'items ' property for DFM-text conversion        
        Writer.WriteStr('Items');                      
        // !!! write all the collection items and subobjects !!!   
        Writer.WriteCollection(self);                  

        Writer.WriteListEnd;
        Writer.WriteListEnd; // ...The 'End'...                                 
      except
        raise TmxCollectionError.Create('SaveToStream() - error writing collection!');
      end;  
    finally
      Writer.Free;
    end;
    MemoryStream.Position := 0;                        // make ready to convert
    if not asBinary then
    begin
      format := sofText;                               // set destination format
      ObjectBinaryToText(MemoryStream,aStream,format); // convert to DFM-text
    end else MemoryStream.SaveToStream(aStream);       // copy work stream
  finally
    MemoryStream.Free;
  end;
end;

end.


Es wäre auch denkbar die Collection-daten als header auf angehägte binäre daten zu verwenden etc. Ich würde mich freuen wenn ihr verbesserungsvorschläge und bugfixes hier publik macht ;)


Viel spass damit!

mfg. maximov.

_________________
mfg.
mâximôv


Zuletzt bearbeitet von maximus am Fr 30.07.04 11:52, insgesamt 2-mal bearbeitet
maximus Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Sa 07.02.04 13:24 
Warum sagt mir eigentlich keiner, dass mein 'advanced sample' nicht ohne umstände zu kompilieren ist :? ...in der .DPR hatte ich noch zwei alte einträge vergessen, die ich jetzt entfernt habe!

Also weiterhin viel spass beim kodieren :wink:

_________________
mfg.
mâximôv
mimi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3458

Ubuntu, Win XP
Lazarus
BeitragVerfasst: Mi 28.07.04 14:00 
ich würde mir gerne mal das beispiel anschauen, aber leider kann man das nicht downloaden:
er findet den server nicht !!!

_________________
MFG
Michael Springwald, "kann kein englisch...."
maximus Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 896

Win XP, Suse 8.1
Delphi 4/7/8 alles prof
BeitragVerfasst: Fr 30.07.04 11:49 
Moin mimi,

diese unit ist veraltet! Man sollte statt dessen die dpCollection.pas verwenden:

www.delphipraxis.net...tcollectionitem.html


mfg.

_________________
mfg.
mâximôv