How to store records to a stream for later retrieval (Views: 707)
Problem/Question/Abstract: How to store records to a stream for later retrieval Answer: Stores a record to stream. Record can later be retrieved with RecordFromStream procedure. procedure RecordToStream (DSet: TDataSet; {Dataset in question} Stream: TStream; {Stream to store to} PhysFieldsOnly: Boolean; {Do not store lookup and calculated fields} FieldsNotStore: array of TField); {Additional fields that should not be stored} function DoStoreFld(aFld: TField): Boolean; {Checks whether the field should be stored} var i: Integer; begin Result := not PhysFieldsOnly or (aFld.FieldNo > 0); {FieldNo of Lookup and calculated fields is <= 0} if Result then for i := 0 to High(FieldsNotStore) do if aFld = FieldsNotStore[i] then begin Result := false; break; end; end; procedure WriteFldname(fldname: string); var L: longint; begin L := length(fldname); Stream.Write(L, sizeOf(L)); Stream.Write(fldname[1], L); end; var I, Cnt, Len: Longint; Fld: TField; FldBuff: Pointer; BStream: TBlobStream; begin Cnt := DSet.FieldCount; Getmem(FldBuff, 256); try for i := 1 to Cnt do begin Fld := DSet.Fields[i - 1]; if not DoStoreFld(Fld) then Continue; WriteFldname(Fld.Fieldname); if Fld is TBlobField then begin BStream := TBlobStream.Create(Fld as TBlobField, bmRead); try Len := BStream.Size; Stream.Write(len, SizeOf(Len)); Stream.CopyFrom(BStream, Len); finally BStream.Free; end; end else begin Len := Fld.dataSize; Fld.Getdata(FldBuff); Stream.Write(Len, SizeOf(Len)); Stream.Write(FldBuff^, Len); end; end; Len := 0; {Mark the end of the stream with zero} Stream.Write(Len, SizeOf(Len)); finally Freemem(FldBuff, 256); end; end; Reads record from the stream. The record was previously stored with RecordToStream procedure. Dset must be in edit/insert mode. procedure RecordFromStream (DSet: TDataSet; {Dataset in question} Stream: TStream; {Stream to retrieve from} FieldsToIgnore: array of TField); {Fields that should not be retrieved} function DoReadFld(aFld: tField): Boolean; var i: Integer; begin Result := (aFld <> nil) and (aFld.FieldNo > 0); {calculated and lookup fields are allways ignored} if Result then for i := 0 to High(FieldsToIgnore) do if aFld = FieldsToIgnore[i] then begin Result := false; break; end; end; function ReadFldname: string; var L: longint; begin Stream.Read(L, sizeOf(L)); if L = 0 then result := '' else begin SetLength(Result, L); Stream.Read(Result[1], L); end; end; var Len: Longint; Fld: TField; Fldname: string; FldBuff: Pointer; begin Getmem(FldBuff, 256); try Fldname := ReadFldname; while Fldname <> '' do begin if Fldname = '' then break; Fld := DSet.FindField(Fldname); Stream.Read(Len, SizeOf(Len)); if DoReadFld(Fld) then begin if Fld is TBlobField then begin with TBlobStream.Create(Fld as TBlobField, bmWrite) do try CopyFrom(Stream, Len); finally Free; end; end else begin if Fld.datasize <> Len then raise Exception.CreateFmt('Field size changed: Field: %s', [Fldname]); Stream.Read(FldBuff^, Fld.dataSize); Fld.Setdata(FldBuff); end; end else begin Stream.Seek(Len, soFromCurrent); end; Fldname := ReadFldname; end finally Freemem(FldBuff, 256); end; end; |