首页 考试吧论坛 Exam8视线 考试商城 网络课程 模拟考试 考友录 实用文档 求职招聘 论文下载 | ||
2011中考 | 2011高考 | 2012考研 | 考研培训 | 在职研 | 自学考试 | 成人高考 | 法律硕士 | MBA考试 MPA考试 | 中科院 |
||
四六级 | 职称英语 | 商务英语 | 公共英语 | 托福 | 雅思 | 专四专八 | 口译笔译 | 博思 | GRE GMAT 新概念英语 | 成人英语三级 | 申硕英语 | 攻硕英语 | 职称日语 | 日语学习 | 法语 | 德语 | 韩语 |
||
计算机等级考试 | 软件水平考试 | 职称计算机 | 微软认证 | 思科认证 | Oracle认证 | Linux认证 华为认证 | Java认证 |
||
公务员 | 报关员 | 银行从业资格 | 证券从业资格 | 期货从业资格 | 司法考试 | 法律顾问 | 导游资格 报检员 | 教师资格 | 社会工作者 | 外销员 | 国际商务师 | 跟单员 | 单证员 | 物流师 | 价格鉴证师 人力资源 | 管理咨询师考试 | 秘书资格 | 心理咨询师考试 | 出版专业资格 | 广告师职业水平 驾驶员 | 网络编辑 |
||
卫生资格 | 执业医师 | 执业药师 | 执业护士 | ||
会计从业资格考试(会计证) | 经济师 | 会计职称 | 注册会计师 | 审计师 | 注册税务师 注册资产评估师 | 高级会计师 | ACCA | 统计师 | 精算师 | 理财规划师 | 国际内审师 |
||
一级建造师 | 二级建造师 | 造价工程师 | 造价员 | 咨询工程师 | 监理工程师 | 安全工程师 质量工程师 | 物业管理师 | 招标师 | 结构工程师 | 建筑师 | 房地产估价师 | 土地估价师 | 岩土师 设备监理师 | 房地产经纪人 | 投资项目管理师 | 土地登记代理人 | 环境影响评价师 | 环保工程师 城市规划师 | 公路监理师 | 公路造价师 | 安全评价师 | 电气工程师 | 注册测绘师 | 注册计量师 |
||
缤纷校园 | 实用文档 | 英语学习 | 作文大全 | 求职招聘 | 论文下载 | 访谈 | 游戏 |
13. Error方法
声明:function Error(const Message: String): Boolean; virtual;
Error方法定义在Reader对象的protected部分,它是用于Reader对象的OnError事件。其返回值决定是否继续错误处理过程。如果返回值为True,则表示用程序应当继续错误处理;如果返回值为False,则表示错误情况被忽略。
如果读部件或属性出错。Reader对象调用Error方法。缺省情况下,Error将返回值设为False,然后调用OnError事件处理过程。
TReader对象总是在try…except程序块的except部分,并提供用户忽略错误的机会。Error的使用方法如下:
try
… { 读部件 }
except
on E: Exception do
begin
…{ 执行一些清除操作 }
if Error(E.Message) then raise;
end;
end;
14. OnError事件
声明:property OnError: TReaderError;
当Reader对象读取数据出错时将引发OnError事件。通过处理OnError事件,可以有选择地处理或忽略错误。
传给OnError事件处理过程的最后一个参数是名为Handled的var参数。在缺省情况下,Error方法将Handled置为True。这将阻止错误更进一步处理。如果事件处理过程仍旧将Handled置为False,Reader对象将引发一个EReadError异常事件。
15. SetName方法
声明:procedure SetName(Component: TComponent; var Name: String virtual);
SetName方法允许Reader对象在将从流中读取的部件的Name值赋给部件的Name属性前修改Name值。ReadComponent方法在读取部件的属性值和其它数据前先读部件的类型和名字在读完名字后,ReadComponent将所读的名字作为Name参数传给SetName,Name 是个var参数,因此SetName能在返回前修改字符串值。SetName还调用了OnSetName事件处理过程,将名字字符串作为var参数传入事件处理过程中,因此,事件处理过程也可修改字符串的值。
16. OnSetName事件
声明:property OnSetName: TSetNameEvent;
OnSetName事件发生在Read对象设置部件的Name属性前,OnSetName事件处理过程的var参数Name参数是一个var参数,因此,事件处理过程再将Name赋给部件前,可以修改Name的值。这对于想过滤窗体中部件的名字是很有帮助的。
下面的OnSetName事件处理过程,命名了名字中包含“Button”的部件,并用“PushButton”替代。
procedure TForm1.ReaderSetName(Reader: TReader; Component: TComponent;
var Name: string);
var
ButtonPos: Integer;
begin
ButtonPos := Pos('Button', Name);
if ButtonPos <> 0 then
Name := Copy(Name, 1, ButtonPos - 1) + 'PushButton' +
Copy(Name, ButtonPos + 6, Length(Name));
end;
17. ReadValue方法
声明:function ReadValue: TValueType;
ReadValue方法读取流中紧着的项目的类型,函数返回后,流的指针移到值类型指示符之后。
TValueType是枚举类型。存储在Filer对象的流中的每个项目之前都有一个字节标识该项目的类型,在读每个项目之前都要读取该字节,以指导调用哪个方法来闱取项目。该字节的值就TValuetype定义的值类型之一。
18. NextValue方法
声明:function Nextvalue: TValuetype;
Nextvalue方法的作用也是返回Reader对象流中紧接着的项目的类型,它与ReadValue的区别在于并不移动指针位置。
19. ReadBoolean方法
声明:function ReadBoolean: Boolean;
ReadBoolean方法从Reader对象的流中读取一个布尔值,并相应地移动流位置指针。
20、ReadChar方法
声明:function ReadChar: char;
ReadChar方法从Reader对象的流中读取一个字符。
21. ReadFloat方法
声明:function ReadFloat: Extended;
ReadFloat方法从流中读取浮点数。
20. ReadIdent方法
声明:function ReadIdent: string;
ReadIdent方法从流中读取标识符。
23. ReadInteger方法
声明:function ReadInteger: Longin
ReadInteger方法从流中读取整型数字。
24.ReadString方法
声明:function Read String: string;
ReadString方法从Reader对象的流中读取一个字符串,并返回字符串中的内容。该字符串是由Writer对象的WriteString方法写入。
20.2.3.2 TReader对象的实现
Filer对象的作用主要是Delphi用来在DFM文件中读写各种类型的数据(包括部件对象)。这些数据的一个本质特征是变长,而且Filer对象将读写数据操作抽象化,包装成对象提供了大量的读写方法,方便了程序的调用。因此在应用程序中可以广泛使Filer对象,充分利用Delphi的面向对象技术。而且Filer对象与Stream对象捆绑在一起,一方面可以在各种存储媒介中存取任意格式的数据;另一方面,由于充分利用面向对象的动态联编,各种读写方法的使用方法是一致的,因此,方法调用很简单。下面我们着重介绍Reader 对象中与读写数据操作有关的属性和方法的实现。
1. TReader属性的实现
在TReader对象的属性实现中我们重点介绍Position的实现。
Position属性的定义了使用了读写控制,它们分别是GetPosition和SetPosition方法。
TReader = class(TFiler)
private
…
function GetPosition: Longint;
procedure SetPosition(Value: Longint);
public
…
property Position: Longint read GetPosition write SetPosition;
end;
Postition的读写控制方法如下:
function TReader.GetPosition: Longint;
begin
Result := FStream.Position + FBufPos;
end;
procedure TReader.SetPosition(Value: Longint);
begin
FStream.Position := Value;
FBufPos := 0;
FBufEnd := 0;
end;
在TReader的父对象TFiler对象中介绍过FBufPos和FBufEnd变量。Filer对象内部分配了一个BufSize大小的缓冲区FBufPos就是指在缓冲区中的相对位置,FBufEnd是指在缓冲区中数据结束处的位置(缓冲区中的数据不一定会充满整个缓冲区)。
在GetPosition方法中可以看到Reader对象的Position值和Stream对象的Position值是不同的。Reader对象多了一个FButPos的编移量。
2. Defineproperty和DefineBinaryproperty方法的实现
这两个方法是虚方法,在TFiler中是抽象方法,在TReader和TWriter对象中才有具体的实现。
它们在TReader中的实现如下:
procedure TReader.DefineProperty(const Name: string; ReadData: TReaderProc;
WriteData: TWriterProc; HasData: Boolean);
begin
if CompareText(Name, FPropName) = 0 then
begin
ReadData(Self);
FPropName := '';
end;
end;
procedure TReader.DefineBinaryProperty(const Name: string;
ReadData, WriteData: TStreamProc; HasData: Boolean);
var
Stream: TMemoryStream;
Count: Longint;
begin
if CompareText(Name, FPropName) = 0 then
begin
if ReadValue <> vaBinary then
begin
Dec(FBufPos);
SkipValue;
FCanHandleExcepts := True;
PropValueError;
end;
Stream := TMemoryStream.Create;
try
Read(Count, SizeOf(Count));
Stream.SetSize(Count);
Read(Stream.Memory^, Count);
FCanHandleExcepts := True;
ReadData(Stream);
finally
Stream.Free;
end;
FPropName := '';
end;
end;
在两个方法都将Name参数值与当前的属性名比较,如果相同则进行读操作。在DefineBinaryproperty中,创建了一个内存流。先将数据读到内存流中然后调用ReadData读取数据。
3. FlushBuffer的实现
FlushBuffer方法用于清除Reader对象的内部缓冲区中的内容,保持Reader对象和流在位置(Position)上的同步,其实现如下:
procedure TReader.FlushBuffer;
begin
FStream.Position := FStream.Position - (FBufEnd - FBufPos);
FBufPos := 0;
FBufEnd := 0;
end;
4. ReadListBegin、ReadListEnd和EndOfList方法
这三个方法都是用于从Reader对象的流中读取一连串的项目,并且这些项目都由WriteListBegin写入的标志标定开始和WriteListEnd写入标志,标定结束,在读循环中用EndOfList进行判断。它们是在Reader对象读取流中数据时经常用于的。它们的实现如下:
procedure TReader.ReadListBegin;
begin
CheckValue(vaList);
end;
procedure TReader.ReadListEnd;
begin
CheckValue(vaNull);
end;
function TReader.EndOfList: Boolean;
begin
Result := ReadValue = vaNull;
Dec(FBufPos);
end;
项目表开始标志是VaList,项目表结束标志是VaNull,VaList和VaNull都是枚举类型TValueType定义的常量。
它们实现中调用的CheckValue是TReader的私有方法,其实现如下:
procedure TReader.CheckValue(Value: TValueType);
begin
if ReadValue <> Value then
begin
Dec(FBufPos);
SkipValue;
PropValueError;
end;
end;
CheckValue方法的功能是检测紧接着要读的值是否是Value指定的类型。如果不是则跳过该项目并触发一个SInvalidPropertyValue错误。
EndOfList函数只是简单地判断下一字节是否是VaNull将判断结果返回,并将字节移回原来位置。
5. 简单数据类型读方法的实现
简单数据类型指的是布尔型、字符型、整型、字符串型、浮点型、集合类型和标识符。将它们放在一起介绍是因为它们的实现方法类似。
因为它们的实现都用到了ReadValue方法,因此先来介绍ReadValue方法的实现:
function TReader.ReadValue: TValueType;
begin
Read(Result, SizeOf(Result));
end;
该方法调用私有方法Read,从Reader对象流中读一个字节,并移动位置指针。
ReadValue方法专门从流中读取值的类型的,所有的数据读写方法中在读取数据前都要调用ReadValue方法判断是否是所要读的数据。如果是,则调用Read方法读取数据;否则触发一个异常事件,下面看Integer类型的读方法:
function TReader.ReadInteger: Longint;
var
S: Shortint;
I: Smallint;
begin
case ReadValue of
vaInt8:
begin
Read(S, SizeOf(Shortint));
Result := S;
end;
vaInt16:
begin
Read(I, SizeOf(I));
Result := I;
end;
vaInt32:
Read(Result, SizeOf(Result));
else
PropValueError;
end;
end;
因为Delphi 2.0中,整型可分8位、16位和32位,因此读取整型数据时分别作了判断。
布尔类型的数据是直接放在值类型标志上,如果类型为VaTrue,则值为True;如果类型为VaFalse,则值为False。
function TReader.ReadBoolean: Boolean;
begin
Result := ReadValue = vaTrue;
end;
ReadString方法也利用ReadValue方法判断是字符串还是长字符串。
function TReader.ReadString: string;
var
L: Integer;
begin
L := 0;
case ReadValue of
vaString:
Read(L, SizeOf(Byte));
vaLString:
Read(L, SizeOf(Integer));
else
PropValueError;
end;
SetString(Result, PChar(nil), L);
Read(Pointer(Result)^, L);
end;
如果VaString类型紧接着一个字节存有字符串的长度;如果是VaLString类,则紧接着两个字节存放字符串长度,然后根据字符串长度用SetString过程给分配空间,用Read方法读出数据。
ReadFloat方法允许将整型值转换为浮点型。
function TReader.ReadFloat: Extended;
begin
if ReadValue = vaExtended then Read(Result, SizeOf(Result)) else
begin
Dec(FBufPos);
Result := ReadInteger;
end;
end;
字符类型数据设有直接的标志,它是根据VaString后面放一个序值为1的字节来判断的。
function TReader.ReadChar: Char;
begin
CheckValue(vaString);
Read(Result, 1);
if Ord(Result) <> 1 then
begin
Dec(FBufPos);
ReadStr;
PropValueError;
end;
Read(Result, 1);
end;
出于读取DFM文件需要,Filer对象支持读取标识符。
function TReader.ReadIdent: string;
var
L: Byte;
begin
case ReadValue of
vaIdent:
begin
Read(L, SizeOf(Byte));
SetString(Result, PChar(nil), L);
Read(Result[1], L);
end;
vaFalse:
Result := 'False';
vaTrue:
Result := 'True';
vaNil:
Result := 'nil';
else
PropValueError;
end;
end;
一般说来,各种复杂的数据结构都是由这些简单数据组成;定义了这些方法等于给读各种类型的数据提供了元操作,使用很方便。例如,读取字符串类型的数据时,如果采用传流方法还要判断字符串的长度,使用ReadString方法就不同了。但应该特别注意的是这些类型数据的存储格式是由Delphi设计的与简单数据类型有明显的不同。因此,存入数据时应当使用Writer对象相应的方法,而且在读数据前要用NextValue方法进行判断,否则会触发异常事件。
6. 读取部件的方法的实现
Reader对象中用于读取部件的方法有ReadSignature、ReadPrefix、ReadComponent、ReadRootComponent和ReadComponents。
ReadSignature方法主要用于读取Delphi Filer对象标签一般在读取部件前,都要用调用ReadSignature方法以指导部件读写过程。
procedure TReader.ReadSignature;
var
Signature: Longint;
begin
Read(Signature, SizeOf(Signature));
if Signature <> Longint(FilerSignature) then ReadError(SInvalidImage);
end;
FilerSignature就是Filer对象标签其值为“TPF0” ,如果读的不是“TPF0” ,则会触发SInValidImage异常事件。
ReadPrefix方法是用于读取流中部件前的标志位,该标志表示该部件是否处于从祖先窗体中继承的窗体中和它在窗体中的位置是否很重要。
procedure TReader.ReadPrefix(var Flags: TFilerFlags; var AChildPos: Integer);
var
Prefix: Byte;
begin
Flags := [];
if Byte(NextValue) and $F0 = $F0 then
begin
Prefix := Byte(ReadValue);
Byte(Flags) := Prefix and $0F;
if ffChildPos in Flags then AChildPos := ReadInteger;
end;
end;
TFilerFlags的定义是这样的:
TFilerFlag = (ffInherited, ffChildPos);
TFilerFlags = Set of TFilerFlag;
充当标志的字节的高四位是$F,低四位是集合的值,也是标志位的真正含义。如果ffChildPos置位,则紧接着的整型数字中放着部件在窗体中的位置序值。
ReadComponent方法用于从Reader对象的流中读取部件。Component 参数指定了要从流中读取的对象。函数返回所读的部件。
function TReader.ReadComponent(Component: TComponent): TComponent;
var
CompClass, CompName: string;
Flags: TFilerFlags;
Position: Integer;
…
begin
ReadPrefix(Flags, Position);
CompClass := ReadStr;
CompName := ReadStr;
Result := Component;
if Result = nil then
if ffInherited in Flags then
FindExistingComponent else
CreateComponent;
if Result <> nil then
try
Include(Result.FComponentState, csLoading);
if not (ffInherited in Flags) then SetCompName;
if Result = nil then Exit;
Include(Result.FComponentState, csReading);
Result.ReadState(Self);
Exclude(Result.FComponentState, csReading);
if ffChildPos in Flags then Parent.SetChildOrder(Result, Position);
FLoaded.Add(Result);
except
if ComponentCreated then Result.Free;
raise;
end;
end;
ReadCompontent方法首先调用ReadPrefix方法,读出部件标志位和它的创建次序值(Create Order)。然后用ReadStr方法分别读出部件类名和部件名。如果Component参数为nil,则执行两个任务:
● 如果ffInberited 置位则从Root 找已有部件,否则,就从系统的Class表中找到该部件类型的定义并创建
● 如果结果不为空,将用部件的ReadState方法读入各种属性值,并设置部件的Parent 属性,并恢复它在Parent部件的创建次序。
相关推荐:2010年9月计算机等级考试试题及答案解析专题北京 | 天津 | 上海 | 江苏 | 山东 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
广东 | 河北 | 湖南 | 广西 | 河南 |
海南 | 湖北 | 四川 | 重庆 | 云南 |
贵州 | 西藏 | 新疆 | 陕西 | 山西 |
宁夏 | 甘肃 | 青海 | 辽宁 | 吉林 |
黑龙江 | 内蒙古 |