第二十章开发Delphi对象式数据管理功能三.docx
- 文档编号:8838239
- 上传时间:2023-02-02
- 格式:DOCX
- 页数:14
- 大小:21.08KB
第二十章开发Delphi对象式数据管理功能三.docx
《第二十章开发Delphi对象式数据管理功能三.docx》由会员分享,可在线阅读,更多相关《第二十章开发Delphi对象式数据管理功能三.docx(14页珍藏版)》请在冰豆网上搜索。
第二十章开发Delphi对象式数据管理功能三
20.2.1.1TFiler对象的属性和方法
1.Root属性
声明:
propertyRoot:
TComponent;
Root属性给Filer对象指出被读写的对象中哪一个对象是根或主要拥有者。
RootComponent和WriteRootComponent方法在读和写部件及其拥有的部件前先设置Root的值。
2.Ancestor属性
声明:
propertyAncestor:
TPersistent;
Ancestor属性用于往继承下来的窗体中写部件,因为当写部件时,Write对象只需要写入与所继承的部件不同的属性,所以在写之前要跟踪每个继承的部件,并且比较它们的属性。
如果Ancestor为nil,就表示没有相应的继承的部件,Writer对象应当将部件完全写入流。
Ancestor一般为nil,只有当调用WriteDescendant和WriteDescendantRes时,才给赋值。
当编写和覆盖DefineProperties时,必须设置Ancestor的值。
3.IgnoreChildren属性
声明:
propertyIgnorechildren:
Boolean;
IgnoreChildren属性使一个Writer对象存储部件时可以不存储该部件拥有的部件。
如果IgnoreChildren属性为True,则Writer对象存储部件不存它拥有的子部件。
否则,Writer对象将所有其拥有的对象写入流。
4.Create方法
声明:
constructorCreate(Stream:
TStream;BufSize:
Cardinal);
Create方法创建一个新的Filer对象,建立它和流Stream的联系;并且给它分配一个缓冲区Buffer。
Buffer的大小由BufSize指定。
5.Defineproperty方法
声明:
procedureDefineproperty(constName:
String;ReadData:
TReaderProc;
WriteData:
TWriterProc;HasData:
Boolean);virtual;abstract;
Defineproperty方法定义Filer对象将作为属性存储的数据。
Name参数描述接受的属性名,该属性不在published部分定义。
ReadData和WriteData参数指定在存取对象时读和写所需数据的方法。
HasData参数在运行时决定了属性是否有数据要存储。
只有当对象有数据要存储时,才在该对象的DefineProperties中调用DefineProperty。
DefineProperties有一个Filer对象作为它的参数,调用的就是该Filer对象的DefineProperty和DefineBinaryProperty方法。
当定义属性时,Writer对象应当引用Ancestor属性,如果该属性非空,Writer对象应当只写入与从Ancestor继承的不同的属性的值。
一个最简单的例子是TComponent的DefineProperties方法。
尽管TComponent没有在published中定义Left、Top属性,但该方法存储了部件的位置信息。
procedureTComponent.DefineProperties(Filer:
TFiler);
begin
Filer.DefineProperty('Left',ReadLeft,WriteLeft,LongRec(FDesignInfo).Lo<>0);
Filer.DefineProperty('Top',ReadTop,WriteTop,LongRec(FDesignInfo).Hi<>0);
end;
6.DefineBinaryproperty方法
声明:
procedureDefineBinaryproperty(constName:
String;
ReadData,WriteData:
TStreamProc;
HisData:
Boolean);virtual;abstract;
DefineBinaryProperty方法定义Filer对象作为属性存储的二进制数据。
Name参数描述属性名。
ReadData和WriteData参数描述所存储的对象中读写所需数据的方法。
HasData参数在运行时决定属性是否有数据要存。
DefineBinaryProperty和DefineProperty方法的不同之处在于,二进制型的属性直接用Stream对象读写,而不是通过Filer对象。
通过ReadData和WriteData传入的方法,直接将对象数据写入流或从流读出。
DefineBinaryProperty属性用得较少。
只有标准的VCL对象定义了象图形、图像之类的二进制属性的部件中才用它。
7.FlushBuffer方法
声明:
procedureFlushBuffer;virtual:
abstract;
FlushBuffer方法用于使Filer对象的缓冲区与相联的Stream对象同步。
对Reader对象来说,是通过重新分配缓冲区;对于Writer对象是通过写入当前缓冲区。
FlushBuffer是一个抽象方法,TReader和TWriter都覆盖了它,提供了具体实现。
20.2.1.2TFiler对象的实现原理
TFiler对象是Filer对象的基础类,它定义的大多数方法都是抽象类型的,没有具体实现它,这些方法要在TReader和TWrite中覆盖。
但它们提供了Filer对象的框架,了解它无疑是很重要的。
1.TFiler对象属性的实现
TFiler对象定义了三个属性:
Root、Ancestor和IgnoreChildren。
正如定义对象属性通常所采用的方法那样,要在private部分定义存储属性值的数据域,然后在public或Published部分定义该属性,并按需要增加读写控制。
它们的定义如下:
TFiler=class(TObject)
private
…
FRoot:
TComponent;
FAncestor:
TPersistent;
FIgnoreChildren:
Boolean;
public
…
propertyRoot:
TComponentreadFRootwriteFRoot;
propertyAncestor:
TPersistentreadFAncestorwriteFAncestor;
propertyIgnoreChildren:
BooleanreadFIgnoreChildrenwriteFIgnoreChildren;
end;
它们在读写控制上都是直接读写私有的数据域。
在介绍TReader和TWriter的实现,我们还会看到这几个属性的原理介绍。
2.TFiler对象方法的实现
在TFiler对象定义的众多方法中很多都是抽象类方法,没有具体实现。
在TFiler的后继对象TReader中覆盖了这些方法。
在后面章节,会介绍这些方法的实现。
在TFiler对象中有具体实现的有两个方法Create和Destroy。
⑴Create方法的实现
Create方法是TFiler的构造方法,它有两个参数Stream和BufSize。
Stream是指定与TFiler对象相联系的Stream对象,Filer对象都是用Stream对象完成具体的读写。
BufSize是TFiler对象内部开设的缓冲区的大小。
Filer对象内部开设缓冲区是为了加快数据的读写,它的实现如下:
constructorTFiler.Create(Stream:
TStream;BufSize:
Integer);
begin
FStream:
=Stream;
GetMem(FBuffer,BufSize);
FBufSize:
=BufSize;
end;
FStream、FBuffer和FBufSize都是TFiler在private部分定义的数据域。
FStream表示与Filer对象相联的Stream对象,FBuffer指向Filer对象内部开设的缓冲区,FBufSize是内部缓冲区的大小。
Create方法用Stream参数值给FStream赋值,然后用GetMem分配BufSize大小的动态内存作为内部缓冲区。
⑵Destroy方法的实现
Destroy方法是TFiler对象的析构函数,它的作用就是释放动态内存。
destructorTFiler.Destroy;
begin
ifFBuffer<>nilthenFreeMem(FBuffer,FBufSize);
end;
20.2.2TWriter对象
TWriter对象是可实例化的,往流中写数据的Filer对象。
TWriter对象直接从TFiler继承而来,除了覆盖从TFiler继承的方法外,还增加了大量的关于写各种数据类型(如Integer、String和Component等)的方法。
TWriter对象和TReader对象配合使用将使对象读写发挥巨大作用。
20.2.2.1TWriter对象的属性和方法
1.Position属性
声明:
propertyPosition:
Longint;
TWriter对象的Position属性表示相关联的流中的当前要写的位置,TReader对象也有这个属性,但与TReader对象不同的是TWriter对象的Position的值比流的Position值小,这一点一看属性实现就清楚了。
2.RootAncesstor属性
声明:
propertyRootAncestor:
TComponent;
RootAncestor属性表示的是Root属性所指的部件的祖先。
如果Root是继承的窗体,Writer对象将窗体拥有部件与祖先窗体中的相应部件依次比较,然后只写入那些与祖先中的不同的部件。
3.Write方法
声明:
procedureWrite(constBuf;Count:
Longint);
Write方法从Buf中往与Writer相关联的流中写入Count个字节。
4.WriteListBegin方法
声明:
procedureWriteListBegin;
WriteListBegin方法往Write对象的流中写入项目列表开始标志,该标志意味着后面存储有一连串的项目。
Reader对象,在读这一连串项目时先调用ReadListBegin方法读取该标志位,然后用EndOfList判断是否列表结束,并用循环语句读取项目。
在调用WriteListBegin方法的后面必须调用WriteListEnd方法写列表结束标志,相应的在Reader对象中有ReadListEnd方法读取该结束标志。
5.WriteListEnd方法
声明:
procedureWriteListEnd;
WriteListEnd方法在流中,写入项目列表结束标志,它是与WriteListBegin相匹配的方法。
6.WriteBoolean方法
声明:
procedureWriteBoolean(Value:
Boolean);
WriteBoolean方法将Value传入的布尔值写入流中。
7.WriteChar方法
声明:
procedureWriteChar(Value:
char);
WriteChar方法将Value中的字符写入流中。
8.WriteFloat方法
声明:
procedureWriteFloat(Value:
Extended);
WriteFloat方法将Value传入的浮点数写入流中。
9.WriteInteger方法
声明:
procedureWriteInteger(Value:
Longint);
WriteInteger方法将Value中的整数写入流中。
10.WriteString方法
声明:
procedureWriteString(constValue:
string);
WriteString方法将Value中的字符串写入流中。
11.WriteIdent方法
声明:
procedureWriteIdent(constIdent:
string);
WriteIdent方法将Ident传入的标识符写入流中。
12.WriteSignature方法
声明:
procedureWriteSignature;
WriteSignature方法将DelphiFiler对象标签写入流中。
WriteRootComponent方法在将部件写入流之前先调用WriteSignature方法写入Filer标签。
Reader对象在读部件之前调用ReadSignature方法读取该标签以指导读操作。
13.WritComponent方法
声明:
procedureWriteComponent(Component:
TComponent);
WriteComponent方法调用参数Component的WriteState方法将部件写入流中。
在调用WriteState之前,WriteComponent还将Component的ComponetnState属性置为csWriting。
当WriteState返回时再清除csWriting.
14.WriteRootComponent方法
声明:
procedureWriteRootComponent(Root:
TComponent);
WriteRootComponent方法将Writer对象Root属性设为参数Root带的值,然后调用WriteSignature方法往流中写入Filer对象标签,最后调用WriteComponent方法在流中存储Root部件。
20.2.2.2TWriter对象的实现
TWriter对象提供了许多往流中写各种类型数据的方法,这对于程序员来说是很重要的功能。
TWrite对象往流中写数据是依据不同的数据采取不同的格式的。
因此要掌握TWriter对象的实现和应用方法,必须了解Writer对象存储数据的格式。
首先要说明的是,每个Filer对象的流中都包含有Filer对象标签。
该标签占四个字节其值为“TPF0”。
Filer对象为WriteSignature和ReadSignature方法存取该标签。
该标签主要用于Reader对象读数据(部件等)时,指导读操作。
其次,Writer对象在存储数据前都要留一个字节的标志位,以指出后面存放的是什么类型的数据。
该字节为TValueType类型的值。
TValueType是枚举类型,占一个字节空间,其定义如下:
TValueType=(VaNull,VaList,VaInt8,VaInt16,VaInt32,VaEntended,VaString,VaIdent,
VaFalse,VaTrue,VaBinary,VaSet,VaLString,VaNil,VaCollection);
因此,对Writer对象的每一个写数据方法,在实现上,都要先写标志位再写相应的数据;而Reader对象的每一个读数据方法都要先读标志位进行判断,如果符合就读数据,否则产生一个读数据无效的异常事件。
VaList标志有着特殊的用途,它是用来标识后面将有一连串类型相同的项目,而标识连续项目结束的标志是VaNull。
因此,在Writer对象写连续若干个相同项目时,先用WriteListBegin写入VaList标志,写完数据项目后,再写出VaNull标志;而读这些数据时,以ReadListBegin开始,ReadListEnd结束,中间用EndofList函数判断是否有VaNull标志。
下面就介绍它们的实现。
1.TWriter对象属性的实现
TWriter对象直接从TFiler对象继承,它只增加了Position和RootAncestor属性。
RootAncestor属性在private部分有数据域FRootAncestor存入其值。
在属性定义的读与控制上都是直接读取该值。
Position属性的定义中包含了两个读写控制方法:
GetPosition和SetPosition:
TWriter=class(TFiler)
private
FRootAncestor:
TComponent;
…
functionGetPosition:
Longint;
procedureSetPosition(Value:
Longint);
public
…
propertyPosition:
LongintreadGetPositionwriteSetPosition;
propertyRootAncestor:
TComponentreadFRootAncestorwriteFRootAncestor;
end;
GetPosition和SetPosition方法实现如下:
functionTWriter.GetPosition:
Longint;
begin
Result:
=FStream.Position+FBufPos;
end;
procedureTWriter.SetPosition(Value:
Longint);
var
StreamPosition:
Longint;
begin
StreamPosition:
=FStream.Position;
{只清除越界的缓冲区}
if(Value
begin
WriteBuffer;
FStream.Position:
=Value;
end
elseFBufPos:
=Value-StreamPosition;
end;
WriteBuffer是TWriter对象定义的私有方法,它的作用是将Writer对象内部缓冲区中的有效数据写入流中,并将FBufPos置为0。
Writer对象的FlushBuffer对象就是用WriteBuffer方法刷新缓冲区。
在SetPosition方法中,如果Value值超出了边界(FStream.Position,FStream.Position+FBufPos),就将缓冲区中的内容写入流,重新设置缓冲区在流中的相对位置;否则,就只是移动FBufPos指针。
2.TWriter方法的实现
⑴WriteListBegin和WriteListEnd的实现
这两个方法都是用于写连续若干个相同类型的值。
WriteListBegin写入VaList标志,WriteListEnd写入VaNull标志。
procedureTWriter.WriteListBegin;
begin
WriteValue(vaList);
end;
procedureTWriter.WriteListEnd;
begin
WriteValue(vaNull);
end;
这两个方法都调用TWriter对象的WriteValue方法,该方法主要用于写入TValueType类型的值。
procedureTWriter.WriteValue(Value:
TValueType);
begin
Write(Value,SizeOf(Value));
end;
⑵简单数据类型的写入
简单数据类型指的是整型、字符型、字符串型、浮点型、布尔型等。
TWriter对象都定义了相应的写入方法。
WriteInteger方法用于写入整型数据。
procedureTWriter.WriteInteger(Value:
Longint);
begin
if(Value>=-128)and(Value<=127)then
begin
WriteValue(vaInt8);
Write(Value,SizeOf(Shortint));
endelse
if(Value>=-32768)and(Value<=32767)then
begin
WriteValue(vaInt16);
Write(Value,SizeOf(Smallint));
endelse
begin
WriteValue(vaInt32);
Write(Value,SizeOf(Longint));
end;
end;
WriteInteger方法将整型数据分为8位、16位和32位三种,并分别用vaInt8、vaInt16和VaInt32。
WriteBoolean用于写入布尔型数据:
procedureTWriter.WriteBoolean(Value:
Boolean);
begin
ifValuethen
WriteValue(vaTrue)else
WriteValue(vaFalse);
end;
与其它数据类型不同的是布尔型数据只使用了标志位是存储布尔值,在标志位后没有数据。
WriteFloat方法用于写入浮点型数据。
procedureTWriter.WriteFloat(Value:
Extended);
begin
WriteValue(vaExtended);
Write(Value,SizeOf(Extended));
end;
字符串“True”、“False”和“nil”作为标识符传入是由于Delphi的特殊需要。
如果是“True”、“False”和“nil”则写入VaTrue、VaFalse和VaNil,否则写入VaIdent标志,接着以字符串形式写入标识符。
WriteString方法用于写入字符串
procedureTWriter.WriteString(constValue:
string);
var
L:
Integer;
begin
L:
=Length(Value);
ifL<=255then
begin
WriteValue(vaString);
Write(L,SizeOf(Byte));
endelse
begin
WriteValue(vaLString);
Write(L,SizeOf(Integer));
end;
Write(Pointer(Value)^,L);
end;
Delphi的字符串类型有两种。
一种长度小于256个字节,另一种长度小于65536个字节。
WriteString方法区分这两类情况存储字符串,一种设置VaStirng标志,另一种设置VaLSt
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第二十 开发 Delphi 对象 数据管理 功能