首頁 考試吧論壇 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月計算機等級考試試題及答案解析專題北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內蒙古 |