20.2.2.2 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 write SetPosition;
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指針。