STREAM
Contents of this page
DATA.PAS
{************************************************}
{ }
{ UNIT DATA }
{ Copyright (c) 1997 by Tom Wellige }
{ Donated as FREEWARE }
{ }
{ E-Mail: wellige@geocities.com }
{ }
{************************************************}
{ Example unit for managing data inside of objects and }
{ TCollections. }
{ }
{ Freeware, Author: Tom Wellige }
{ }
{ This unit will be used in the DEMO.PAS program which is }
{ part of this package. The unit defines the data object }
{ TDATA with all its fields and methodes. }
unit Data;
{$O+,F+}
interface
uses objects;
type
PData = ^TData;
TData = object(TObject)
{ These are the data fields of the object. }
AnyInteger: integer;
AnyWord: integer;
AnyString: string;
{ In addition to records an object defines a number of methodes
to handle the data being stored in it. You have now all data and
the needed functionality at the same place. }
constructor Init(AInteger: integer; AWord: word; AString: string);
constructor Load(var S: TStream);
destructor Done; virtual;
procedure Store(var S: TStream);
procedure SetData(AInteger: integer; AWord: word; AString: string);
procedure GetData(var AInteger: integer; var AWord: word; var AString: string);
end;
{ Defining TData as a descent of TObject has one big advantage:
TObject is able to initilize all it's fields. This is sometihng
Pascal can't ! }
{ This procedure is ncessary to be able to use TData and TCollection
with TStreams. }
procedure Register;
const
{ This is the TData ID in the datastream of TStream. }
RData: TStreamRec = (
ObjType: 1000;
VmtLink: Ofs(TypeOf(TData)^);
Load: @TData.Load;
Store: @TData.Store
);
implementation
constructor TData.Init(AInteger: integer; AWord: word; AString: string);
begin
{ With Init everything starts. Here will our object be initialized. }
inherited Init;
AnyInteger:= AInteger;
AnyWord:= AWord;
AnyString:= AString;
end;
constructor TData.Load(var S: TStream);
var
t: string;
c: word;
begin
{ With the Load method the object is able to load itself (i.e. it's data)
from a stream. To do so the object must first initialize itself and then
read every data field from the stream. }
inherited Init;
S.read(AnyInteger, SizeOf(AnyInteger));
S.read(AnyWord, SizeOf(AnyWord));
S.read(AnyString, SizeOf(AnyString));
end;
destructor TData.Done;
begin
{ At this point one can release memory which is being
dynamically being used by the object. }
inherited Done;
end;
procedure TData.Store(var S: TStream);
begin
{ At this point the object stores itself (i.e. it's data) into a
stream. }
S.write(AnyInteger, SizeOf(AnyInteger));
S.write(AnyWord, SizeOf(AnyWord));
S.write(AnyString, SizeOf(AnyString));
end;
{ The following methods be one of the ideas of object orientated
programming: capsulation. A program or any other object
will *never* access any data inside of an data object directly. It
instead uses the data object's methods to do so.
This has one advantage: the data object will know best of all how
to access it's own data. }
procedure TData.SetData(AInteger: integer; AWord: word; AString: string);
begin
{ Set new data values. }
if AInteger <> 0 then AnyInteger:= AInteger;
if AWord <> 0 then AnyWord:= AWord;
if AString <> '' then AnyString:= AString
end;
procedure TData.GetData(var AInteger: integer; var AWord: word;
var AString: string);
begin
{ Get current data values. }
AInteger:= AnyInteger;
AWord:= AnyWord;
AString:= AnyString;
end;
procedure Register;
begin
{ From OBJECTS.PAS. Registers TObject and TCollection }
RegisterObjects;
{ Register our own new data object TData. }
RegisterType(RData);
end;
end.
DEMO.PAS
{************************************************}
{ }
{ PROGRAM DEMO }
{ Copyright (c) 1997 by Tom Wellige }
{ Donated as FREEWARE }
{ }
{ E-Mail: wellige@geocities.com }
{ }
{************************************************}
{ Example program for handling datas inside of objects and }
{ TCollections. }
{ }
{ Freeware, Author: Tom Wellige }
{ }
{ The unit DATA provides a TDATA object which holds a single }
{ data record. A TCollection object from the OBJECTS unit }
{ manages all data objects in a linked list. A TStream }
{ object is used to store/restore all data records on the }
{ disk. }
{ }
{ To do so, TStreams puts the TCollection which puts each }
{ single TData object. The TData object knows by it's own }
{ how to read from and write itself into a file. }
program DEMO;
uses Crt, Objects, Data;
var
c: char;
{ This list holds all data records }
Liste: PCollection;
const
DateiName: string = 'ANYDATA.DAT';
{ Eine simple Screen }
procedure Screen;
begin
clrscr;
writeln('Select:');
writeln('-------');
writeln;
writeln(' 1 - Input Data');
writeln;
writeln(' 2 - List Data (single record)');
writeln(' 3 - List data (all)');
writeln;
writeln(' 4 - Delete Data (single record)');
writeln(' 5 - Delete Data (all)');
writeln;
writeln(' 6 - Load Data from Disk');
writeln(' 7 - Write Data on Disk');
writeln;
writeln(' ESC - Quit');
writeln;
end;
{ Input Data }
procedure Input;
var
AInteger: integer;
AWord: word;
AString: string;
Data: PData;
begin
clrscr;
writeln('Input Data:');
writeln('-----------');
writeln;
write (' An Integer: '); readln(AInteger);
write (' A Word : '); readln(AWord);
write (' A String : '); readln(AString);
Data:= New(PData, Init(AInteger, AWord, AString));
Liste^.Insert(Data);
Screen;
end;
{ List Data (single record) }
procedure ListSingle;
var
Index: Word;
Data: PData;
AInteger: integer;
AWord: word;
AString: string;
begin
clrscr;
writeln('List Data:');
writeln('----------');
writeln;
{ Any data in the Collection ? }
if Liste^.Count = 0 then
begin
writeln(' The list is empty.');
writeln;
end else
begin
writeln(' There are ', Liste^.Count, ' data records in the list.');
writeln;
repeat
write(' Number of data record: '); readln(Index);
until (Index > 0) and (Index <= Liste^.Count);
writeln;
writeln(' Data Record No. ', Index);
{ The first data record in the list has the index 0 }
Data:= Liste^.At(Index-1);
Data^.GetData(AInteger, AWord, AString);
{ This would also work:
AInteger:= Data^.AnyInteger;
AWord:= Data^.AnyWord;
AString:= Data^.AnyString;
But this not the idea of OOP. Surley will each single case
decides which way will be the best: indirect or direct data
access. }
writeln;
writeln(' Integer: ', AInteger);
writeln(' Word : ', AWord);
writeln(' String : ', AString);
end;
writeln;
writeln(' Press any key...');
readkey;
Screen;
end;
{ List Data (all) }
procedure ListAll;
var
Index: word;
Data: PData;
AInteger: integer;
AWord: word;
AString: string;
begin
clrscr;
writeln('List Data:');
writeln('----------');
writeln;
{ Any data in the Collection ? }
if Liste^.Count = 0 then
begin
writeln(' The list is empty.');
writeln;
end else
begin
writeln(' There are ', Liste^.Count, ' data records in the list.');
writeln;
for Index:= 0 to Liste^.Count-1 do
begin
Data:= Liste^.At(Index);
Data^.Getdata(AInteger, AWord, AString);
writeln(' ', Index+1, ': Integer: ', AInteger:5, ' Word: ',
AWord:5, ' String: ', AString);
end;
end;
writeln;
writeln(' Press any key...');
readkey;
Screen;
end;
{ Delete Data (single record) }
procedure DeleteSingle;
var
Index: Word;
begin
clrscr;
writeln('Delete Data:');
writeln('------------');
writeln;
{ Any data in the Collection ? }
if Liste^.Count = 0 then
begin
writeln(' The list is empty.');
writeln;
end else
begin
writeln(' There are ', Liste^.Count, ' data records in the list.');
writeln;
repeat
write(' Number of data record: '); readln(Index);
until (Index > 0) and (Index <= Liste^.Count);
Liste^.AtFree(Index-1);
writeln(' Data record deleted.');
writeln;
end;
writeln;
writeln(' Press any key...');
readkey;
Screen;
end;
{ Delete Data (all) }
procedure DeleteAll;
begin
clrscr;
writeln('Delete Data:');
writeln('------------');
writeln;
{ Any data in the Collection ? }
if Liste^.Count = 0 then
begin
writeln(' The list is empty.');
writeln;
end else
begin
Liste^.FreeAll;
writeln(' All data records deleted.');
writeln;
end;
writeln;
writeln(' Press any key...');
readkey;
Screen;
end;
{ Load dat from stream, i.e. file }
procedure Load;
var
S: PStream;
P: PCollection;
begin
P:= nil;
{ Open the stream }
S:= New(PBufStream, Init(DateiName, stOpenRead, 1024));
if S^.Status = stOk then
begin
{ Load Collection from stream }
P:= PCollection(S^.Get);
if S^.Status <> stOk then
begin
writeln;
write(#7);
writeln(' ERROR LOADING DATA !');
end else
begin
writeln;
writeln(' ', P^.Count, ' data records loaded from file.');
end;
end else
begin
writeln;
write(#7);
writeln(' ERROR OPEN FILE !');
end;
Dispose(S, Done);
{ Did we have loaded a Collection including their dat from
the stream successfully ? }
if P <> nil then
begin
{ delete old list }
Dispose(Liste, Done);
{ repleace with new list }
Liste:= P;
end;
end;
{ Save data in stream, i.e. file }
procedure Store;
var
S: PStream;
begin
{ Open the stream }
S:= New(PBufStream, Init(DateiName, stCreate, 1024));
if S^.Status = stOk then
begin
{ put Collection including their data into stream }
S^.Put(Liste);
if S^.Status <> stOk then
begin
writeln;
write(#7);
writeln(' ERROR WRITING DATA !');
end;
end else
begin
writeln;
write(#7);
writeln(' ERROR OPEN FILE !');
end;
Dispose(S, Done);
end;
procedure Init;
begin
{ Initialize the Collection (data list). Allocates memory for management
data for 10 data objects. When reaching this amount allocate new
memory for management data for 5 additional data objects. }
Liste:= New(PCollection, Init(10, 5));
{ This is necessary to be able to use TCollection and TData with
a Stream. }
Register;
{ Paint screen }
Screen;
end;
procedure Done;
begin
{ Delete list including it's data }
Dispose(Liste, Done);
end;
begin
Init;
repeat
c:= readkey;
case c of
'1': Input;
'2': ListSingle;
'3': ListAll;
'4': DeleteSingle;
'5': DeleteAll;
'6': Load;
'7': Store;
end;
until c = #27;
Done;
end.