DFM文件中读写 TWriter对象的实现

  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;

function GetPosition: Longint;

procedure SetPosition(Value: Longint);

public

property Position: Longint read GetPosition writeSetPosition;

property RootAncestor: TComponent read FRootAncestor write FRootAncestor;

end;

 

GetPosition和SetPosition方法实现如下:

 

function TWriter.GetPosition: Longint;

begin

Result := FStream.Position + FBufPos;

end;

 

procedure TWriter.SetPosition(Value: Longint);

var

StreamPosition: Longint;

begin

StreamPosition := FStream.Position;

{ 只清除越界的缓冲区 }

if (Value < StreamPosition) or (Value > StreamPosition + FBufPos) then

begin

WriteBuffer;

FStream.Position := Value;

end

else FBufPos := 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标志。

 

procedure TWriter.WriteListBegin;

begin

WriteValue(vaList);

end;

 

procedure TWriter.WriteListEnd;

begin

WriteValue(vaNull);

end;

 

  这两个方法都调用TWriter对象的WriteValue方法,该方法主要用于写入TValueType类型的值。

 

procedure TWriter.WriteValue(Value: TValueType);

begin

Write(Value, SizeOf(Value));

end;

 

  ⑵ 简单数据类型的写入

  简单数据类型指的是整型、字符型、字符串型、浮点型、布尔型等。TWriter对象都定义了相应的写入方法。

  WriteInteger方法用于写入整型数据。

 

procedure TWriter.WriteInteger(Value: Longint);

begin

if (Value >= -128) and (Value <= 127) then

begin

WriteValue(vaInt8);

Write(Value, SizeOf(Shortint));

end else

if (Value >= -32768) and (Value <= 32767) then

begin

WriteValue(vaInt16);

Write(Value, SizeOf(Smallint));

end else

begin

WriteValue(vaInt32);

Write(Value, SizeOf(Longint));

end;

end;

 

  WriteInteger方法将整型数据分为8位、16位和32位三种,并分别用vaInt8、vaInt16和VaInt32。

  WriteBoolean用于写入布尔型数据:

 

procedure TWriter.WriteBoolean(Value: Boolean);

begin

if Value then

WriteValue(vaTrue) else

WriteValue(vaFalse);

end;

 

  与其它数据类型不同的是布尔型数据只使用了标志位是存储布尔值,在标志位后没有数据。

  WriteFloat方法用于写入浮点型数据。

 

procedure TWriter.WriteFloat(Value: Extended);

begin

WriteValue(vaExtended);

Write(Value, SizeOf(Extended));

end;

 

  字符串“True”、“False”和“nil”作为标识符传入是由于Delphi的特殊需要。如果是“True”、“False”和“nil”则写入VaTrue、VaFalse和VaNil,否则写入VaIdent标志,接着以字符串形式写入标识符。

  WriteString方法用于写入字符串

  

procedure TWriter.WriteString(const Value: string);

var

L: Integer;

begin

L := Length(Value);

if L <= 255 then

begin

WriteValue(vaString);

Write(L, SizeOf(Byte));

end else

begin

WriteValue(vaLString);

Write(L, SizeOf(Integer));

end;

Write(Pointer(Value)^, L);

end;

 

  Delphi的字符串类型有两种。一种长度小于256个字节,另一种长度小于65536 个字节。WriteString方法区分这两类情况存储字符串,一种设置VaStirng标志,另一种设置VaLString。然后存储字符串的长度值,最后存储字符串数据。

  WriteChar方法用于写入字符。

  

procedure TWriter.WriteChar(Value: Char);

begin

WriteString(Value);

end;

 

  字符类型的读写是用读写字符串的方法,在读的时候,判断字节数为1时,则为字符型。

  ⑶ 部件的写入

  TWriter对象中与写入部件有关的方法有WriteSignature、WritePrefix、WriteComponent、WriteDescendant和WriteRootComponent。

 WriteSignature方法用于往流中写入Filer对象标签。

 

procedure TWriter.WriteSignature;

begin

Write(FilerSignature, SizeOf(FilerSignature));

end;

 

  FilerStgnature是字符串常量,其值为“TPF0”,代表对象标签。

  WritePrefix方法用于在写入部件前写入ffInherited和ffChildPos标志,这些标志表示部件的继承特征和创建序值特征。

 

procedure TWriter.WritePrefix(Flags: TFilerFlags; AChildPos:Integer);

var

Prefix: Byte;

begin

if Flags <> [] then

begin

Prefix := $F0 or Byte(Flags);

Write(Prefix, SizeOf(Prefix));

if ffChildPos in Flags then WriteInteger(AChildPos);

end;

end;

 

  如果ffChildPos置位,则存入部件在Owner中的创建序值。更详细的信息请参阅TReader的ReadPrefix方法。

  WriteComponent方法往流中写入部件。

 

procedure TWriter.WriteComponent(Component: TComponent);

 

function FindAncestor(const Name: string): TComponent;

begin

end;

 

begin

Include(Component.FComponentState, csWriting);

if Assigned(FAncestorList) then

Ancestor := FindAncestor(Component.Name);

Component.WriteState(Self);

Exclude(Component.FComponentState, csWriting);

end;

 

  方法中用Component的WritState方法写入部件的属性。在写入之前将Component.FComponentState置为csWriting写入完后再将csWriting复位。

  WriteDescendant是根据祖先AAncestor的情况写入部件Root。

 

procedure TWriter.WriteDescendent(Root: TComponent;AAncestor: TComponent);

begin

FRootAncestor := AAncestor;

FAncestor := AAncestor;

FRoot := Root;

WriteSignature;

WriteComponent(Root);

end;

 

方法先调用WriteSignature方法写入Filer对象标签。然后调用WriteComponent将部件Root写入流。

  WriteRootComponent方法则是调用WriteDescendant方法写入部件,只是将后者的Ancestor参数以nil值传入。 

procedure TWriter.WriteRootComponent(Root: TComponent);

begin

WriteDescendent(Root, nil);

end;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值