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:
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...
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:
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:
Delphi-Quelltext
1:
| MyCollection := TmxCollection.Create(TmxCustomItem); |
Die benutzung ist sehr einfach und sollte selbsterklärend sein:
Delphi-Quelltext
1: 2: 3:
| MyCollection.SaveToFile('c:/data.dfm',false); ... 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:
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 mxCollection;
interface
uses classes, SysUtils;
type
TmxCollectionError = class(Exception); TmxCollectionSigWrong = class(TmxCollectionError);
TmxCollection = class(TCollection) private FIgnoreSignature: boolean; protected public function GetFormatSignature: String; virtual;
procedure LoadFromFile(FileName: String; isBinary: Boolean); 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'; end;
procedure TmxCollection.LoadFromFile(FileName: String; isBinary: Boolean); var fileStream : TFileStream; begin fileStream := TFileStream.Create(fileName, $0); 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; try if not isBinary then begin format := sofBinary; ObjectTextToBinary(aStream,MemoryStream,format); end else MemoryStream.LoadFromStream(aStream); MemoryStream.Position := 0; Reader := TReader.Create(MemoryStream,2048); try try Reader.ReadSignature; Reader.ReadStr; formatSig := Reader.ReadStr;
if not FIgnoreSignature and (formatSig <> GetFormatSignature) then raise TmxCollectionSigWrong.Create('Signatures differs from the expected one!'); Reader.ReadStr; Reader.ReadValue; Reader.ReadCollection(self);
Reader.ReadListEnd; Reader.ReadListEnd; 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); try SaveToStream(fileStream, asBinary); finally fileStream.free; end; end;
procedure TmxCollection.SaveToStream(aStream: TStream; asBinary: Boolean); var Writer : TWriter; MemoryStream : TMemoryStream; format : TStreamOriginalFormat; begin MemoryStream := TMemoryStream.Create; try Writer := TWriter.Create(MemoryStream,2048); try try Writer.WriteSignature; Writer.WriteStr(ClassName); Writer.WriteStr(GetFormatSignature); Writer.WriteStr('Items'); Writer.WriteCollection(self);
Writer.WriteListEnd; Writer.WriteListEnd; except raise TmxCollectionError.Create('SaveToStream() - error writing collection!'); end; finally Writer.Free; end; MemoryStream.Position := 0; if not asBinary then begin format := sofText; ObjectBinaryToText(MemoryStream,aStream,format); end else MemoryStream.SaveToStream(aStream); 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.