3. FlushBuffer的實(shí)現(xiàn)
FlushBuffer方法用于清除Reader對(duì)象的內(nèi)部緩沖區(qū)中的內(nèi)容,保持Reader對(duì)象和流在位置(Position)上的同步,其實(shí)現(xiàn)如下:
procedure TReader.FlushBuffer;
begin
FStream.Position := FStream.Position - (FBufEnd - FBufPos);
FBufPos := 0;
FBufEnd := 0;
end;
4. ReadListBegin、ReadListEnd和EndOfList方法
這三個(gè)方法都是用于從Reader對(duì)象的流中讀取一連串的項(xiàng)目,并且這些項(xiàng)目都由WriteListBegin寫(xiě)入的標(biāo)志標(biāo)定開(kāi)始和WriteListEnd寫(xiě)入標(biāo)志,標(biāo)定結(jié)束,在讀循環(huán)中用EndOfList進(jìn)行判斷。它們是在Reader對(duì)象讀取流中數(shù)據(jù)時(shí)經(jīng)常用于的。它們的實(shí)現(xiàn)如下:
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;
項(xiàng)目表開(kāi)始標(biāo)志是VaList,項(xiàng)目表結(jié)束標(biāo)志是VaNull,VaList和VaNull都是枚舉類型TValueType定義的常量。
它們實(shí)現(xiàn)中調(diào)用的CheckValue是TReader的私有方法,其實(shí)現(xiàn)如下:
procedure TReader.CheckValue(Value: TValueType);
begin
if ReadValue <> Value then
begin
Dec(FBufPos);
SkipValue;
PropValueError;
end;
end;
CheckValue方法的功能是檢測(cè)緊接著要讀的值是否是Value指定的類型。如果不是則跳過(guò)該項(xiàng)目并觸發(fā)一個(gè)SInvalidPropertyValue錯(cuò)誤。
EndOfList函數(shù)只是簡(jiǎn)單地判斷下一字節(jié)是否是VaNull將判斷結(jié)果返回,并將字節(jié)移回原來(lái)位置。
5. 簡(jiǎn)單數(shù)據(jù)類型讀方法的實(shí)現(xiàn)
簡(jiǎn)單數(shù)據(jù)類型指的是布爾型、字符型、整型、字符串型、浮點(diǎn)型、集合類型和標(biāo)識(shí)符。將它們放在一起介紹是因?yàn)樗鼈兊膶?shí)現(xiàn)方法類似。
因?yàn)樗鼈兊膶?shí)現(xiàn)都用到了ReadValue方法,因此先來(lái)介紹ReadValue方法的實(shí)現(xiàn):
function TReader.ReadValue: TValueType;
begin
Read(Result, SizeOf(Result));
end;
該方法調(diào)用私有方法Read,從Reader對(duì)象流中讀一個(gè)字節(jié),并移動(dòng)位置指針。
ReadValue方法專門(mén)從流中讀取值的類型的,所有的數(shù)據(jù)讀寫(xiě)方法中在讀取數(shù)據(jù)前都要調(diào)用ReadValue方法判斷是否是所要讀的數(shù)據(jù)。如果是,則調(diào)用Read方法讀取數(shù)據(jù);否則觸發(fā)一個(gè)異常事件,下面看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;
因?yàn)镈elphi 2.0中,整型可分8位、16位和32位,因此讀取整型數(shù)據(jù)時(shí)分別作了判斷。
布爾類型的數(shù)據(jù)是直接放在值類型標(biāo)志上,如果類型為VaTrue,則值為T(mén)rue;如果類型為VaFalse,則值為False。
function TReader.ReadBoolean: Boolean;
begin
Result := ReadValue = vaTrue;
end;
ReadString方法也利用ReadValue方法判斷是字符串還是長(zhǎng)字符串。
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類型緊接著一個(gè)字節(jié)存有字符串的長(zhǎng)度;如果是VaLString類,則緊接著兩個(gè)字節(jié)存放字符串長(zhǎng)度,然后根據(jù)字符串長(zhǎng)度用SetString過(guò)程給分配空間,用Read方法讀出數(shù)據(jù)。
ReadFloat方法允許將整型值轉(zhuǎn)換為浮點(diǎn)型。
function TReader.ReadFloat: Extended;
begin
if ReadValue = vaExtended then Read(Result, SizeOf(Result)) else
begin
Dec(FBufPos);
Result := ReadInteger;
end;
end;
字符類型數(shù)據(jù)設(shè)有直接的標(biāo)志,它是根據(jù)VaString后面放一個(gè)序值為1的字節(jié)來(lái)判斷的。
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文件需要,F(xiàn)iler對(duì)象支持讀取標(biāo)識(shí)符。
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;
一般說(shuō)來(lái),各種復(fù)雜的數(shù)據(jù)結(jié)構(gòu)都是由這些簡(jiǎn)單數(shù)據(jù)組成;定義了這些方法等于給讀各種類型的數(shù)據(jù)提供了元操作,使用很方便。例如,讀取字符串類型的數(shù)據(jù)時(shí),如果采用傳流方法還要判斷字符串的長(zhǎng)度,使用ReadString方法就不同了。但應(yīng)該特別注意的是這些類型數(shù)據(jù)的存儲(chǔ)格式是由Delphi設(shè)計(jì)的與簡(jiǎn)單數(shù)據(jù)類型有明顯的不同。因此,存入數(shù)據(jù)時(shí)應(yīng)當(dāng)使用Writer對(duì)象相應(yīng)的方法,而且在讀數(shù)據(jù)前要用NextValue方法進(jìn)行判斷,否則會(huì)觸發(fā)異常事件。
FlushBuffer方法用于清除Reader對(duì)象的內(nèi)部緩沖區(qū)中的內(nèi)容,保持Reader對(duì)象和流在位置(Position)上的同步,其實(shí)現(xiàn)如下:
procedure TReader.FlushBuffer;
begin
FStream.Position := FStream.Position - (FBufEnd - FBufPos);
FBufPos := 0;
FBufEnd := 0;
end;
4. ReadListBegin、ReadListEnd和EndOfList方法
這三個(gè)方法都是用于從Reader對(duì)象的流中讀取一連串的項(xiàng)目,并且這些項(xiàng)目都由WriteListBegin寫(xiě)入的標(biāo)志標(biāo)定開(kāi)始和WriteListEnd寫(xiě)入標(biāo)志,標(biāo)定結(jié)束,在讀循環(huán)中用EndOfList進(jìn)行判斷。它們是在Reader對(duì)象讀取流中數(shù)據(jù)時(shí)經(jīng)常用于的。它們的實(shí)現(xiàn)如下:
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;
項(xiàng)目表開(kāi)始標(biāo)志是VaList,項(xiàng)目表結(jié)束標(biāo)志是VaNull,VaList和VaNull都是枚舉類型TValueType定義的常量。
它們實(shí)現(xiàn)中調(diào)用的CheckValue是TReader的私有方法,其實(shí)現(xiàn)如下:
procedure TReader.CheckValue(Value: TValueType);
begin
if ReadValue <> Value then
begin
Dec(FBufPos);
SkipValue;
PropValueError;
end;
end;
CheckValue方法的功能是檢測(cè)緊接著要讀的值是否是Value指定的類型。如果不是則跳過(guò)該項(xiàng)目并觸發(fā)一個(gè)SInvalidPropertyValue錯(cuò)誤。
EndOfList函數(shù)只是簡(jiǎn)單地判斷下一字節(jié)是否是VaNull將判斷結(jié)果返回,并將字節(jié)移回原來(lái)位置。
5. 簡(jiǎn)單數(shù)據(jù)類型讀方法的實(shí)現(xiàn)
簡(jiǎn)單數(shù)據(jù)類型指的是布爾型、字符型、整型、字符串型、浮點(diǎn)型、集合類型和標(biāo)識(shí)符。將它們放在一起介紹是因?yàn)樗鼈兊膶?shí)現(xiàn)方法類似。
因?yàn)樗鼈兊膶?shí)現(xiàn)都用到了ReadValue方法,因此先來(lái)介紹ReadValue方法的實(shí)現(xiàn):
function TReader.ReadValue: TValueType;
begin
Read(Result, SizeOf(Result));
end;
該方法調(diào)用私有方法Read,從Reader對(duì)象流中讀一個(gè)字節(jié),并移動(dòng)位置指針。
ReadValue方法專門(mén)從流中讀取值的類型的,所有的數(shù)據(jù)讀寫(xiě)方法中在讀取數(shù)據(jù)前都要調(diào)用ReadValue方法判斷是否是所要讀的數(shù)據(jù)。如果是,則調(diào)用Read方法讀取數(shù)據(jù);否則觸發(fā)一個(gè)異常事件,下面看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;
因?yàn)镈elphi 2.0中,整型可分8位、16位和32位,因此讀取整型數(shù)據(jù)時(shí)分別作了判斷。
布爾類型的數(shù)據(jù)是直接放在值類型標(biāo)志上,如果類型為VaTrue,則值為T(mén)rue;如果類型為VaFalse,則值為False。
function TReader.ReadBoolean: Boolean;
begin
Result := ReadValue = vaTrue;
end;
ReadString方法也利用ReadValue方法判斷是字符串還是長(zhǎng)字符串。
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類型緊接著一個(gè)字節(jié)存有字符串的長(zhǎng)度;如果是VaLString類,則緊接著兩個(gè)字節(jié)存放字符串長(zhǎng)度,然后根據(jù)字符串長(zhǎng)度用SetString過(guò)程給分配空間,用Read方法讀出數(shù)據(jù)。
ReadFloat方法允許將整型值轉(zhuǎn)換為浮點(diǎn)型。
function TReader.ReadFloat: Extended;
begin
if ReadValue = vaExtended then Read(Result, SizeOf(Result)) else
begin
Dec(FBufPos);
Result := ReadInteger;
end;
end;
字符類型數(shù)據(jù)設(shè)有直接的標(biāo)志,它是根據(jù)VaString后面放一個(gè)序值為1的字節(jié)來(lái)判斷的。
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文件需要,F(xiàn)iler對(duì)象支持讀取標(biāo)識(shí)符。
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;
一般說(shuō)來(lái),各種復(fù)雜的數(shù)據(jù)結(jié)構(gòu)都是由這些簡(jiǎn)單數(shù)據(jù)組成;定義了這些方法等于給讀各種類型的數(shù)據(jù)提供了元操作,使用很方便。例如,讀取字符串類型的數(shù)據(jù)時(shí),如果采用傳流方法還要判斷字符串的長(zhǎng)度,使用ReadString方法就不同了。但應(yīng)該特別注意的是這些類型數(shù)據(jù)的存儲(chǔ)格式是由Delphi設(shè)計(jì)的與簡(jiǎn)單數(shù)據(jù)類型有明顯的不同。因此,存入數(shù)據(jù)時(shí)應(yīng)當(dāng)使用Writer對(duì)象相應(yīng)的方法,而且在讀數(shù)據(jù)前要用NextValue方法進(jìn)行判斷,否則會(huì)觸發(fā)異常事件。