在內存、外存和數據庫字段中的管理操作抽象為對象方法,並且充分利用了面向對象技術的優點,應用程序可以相當容易地在各種 Stream 對象中拷貝數據。
下面介紹各種對象的數據和方法及使用方法。
TStream 對象
TStream 對象是能在各種媒介中存儲二進制數據的對象的抽象對象。從 TStream 對象繼承的對象用於在內存、 Windows 資源文件、磁盤文件和數據庫字段等媒介中存儲數據。
Stream 中定義了兩個屬性: Size 和 Position 。它們分別以字節為單位表示的流的大小和當前指針位置。 TStream 中定義的方法用於在各種流中讀、寫和相互拷貝二進制數據。因為所有的 Stream 對象都是從 TStream 中繼承來的,所以在 TStream 中定義的域和方法都能被 Stream 對象調用和訪
問。此外,又由於面向對象技術的動態聯編功能, TStream 為各種流的應用提供了統一的接口,簡化了流的使用;不同 Stream 對象是抽象了對不同存儲媒介的數據上的操作,因此, TStream 的需方法為在不同媒介間的數據拷貝提供了最簡捷的手段。
TStream 的屬性和方法
1. Position 屬性
聲明: property Position: Longint;
Position 屬性指明流中讀寫的當前偏移量。
2. Size 屬性
聲明: property Size: Longint;
Size 屬性指明了以字節為單位的流的的大小,它是只讀的。
3. CopyFrom 方法
聲明: function CopyFrom(Source: TStream; Count: Longint): Longint;
CopyFrom 從 Source 所指定的流中拷貝 Count 個字節到當前流中, 並將指針從當前位置移動 Count 個字節數,函數返回值是實際拷貝的字節數。
4. Read 方法
聲明: function Read(var Buffer; Count: Longint): Longint; virtual; abstract;
Read 方法從當前流中的當前位置起將 Count 個字節的內容復制到 Buffer 中,並把當前指針向后移動 Count 個字節數,函數返回值是實際讀的字節數。如果返回值小於 Count ,這意味着讀操作在讀滿所需字節數前指針已經到達了流的尾部。
Read 方法是抽象方法。每個后繼 Stream 對象都要根據自己特有的有關特定存儲媒介的讀操作覆蓋該方法。而且流的所有其它的讀數據的方法(如: ReadBuffer , ReadComponent 等)在完成實際的讀操作時都調用了 Read 方法。面向對象的動態聯編的優點就體現在這兒。因為后繼 Stream 對
象只需覆蓋 Read 方法,而其它讀操作 ( 如 ReadBuffer 、 ReadComponent 等 ) 都不需要重新定義,而且 TStream 還提供了統一的接口。
5. ReadBuffer 方法
聲明: procedure ReadBuffer(var Buffer; Count: Longint);
ReadBuffer 方法從流中將 Count 個字節復制到 Buffer 中, 並將流的當前指針向后移動 Count 個字節。如讀操作超過流的尾部, ReadBuffer 方法引起 EReadError 異常事件。
6. ReadComponent 方法
聲明: function ReadComponent(Instance: TComponent): TComponent;
ReadComponent 方法從當前流中讀取由 Instance 所指定的部件,函數返回所讀的部件。 ReadComponent 在讀 Instance 及其擁有的所有對象時創建了一個 Reader 對象並調用它的 ReadRootComponent 方法。
如果 Instance 為 nil , ReadComponent 的方法基於流中描述的部件類型信息創建部件,並返回新創建的部件。
7. ReadComponentRes 方法
聲明: function ReadComponentRes(Instance: TComponent): TComponent;
ReadComponentRes 方法從流中讀取 Instance 指定的部件,但是流的當前位置必須是由 WriteComponentRes 方法所寫入的部件的位置。
ReadComponentRes
首先調用 ReadResHeader 方法從流中讀取資源頭,然后調用 ReadComponent 方法讀取 Instance 。如果流的當前位置不包含一個資源頭。 ReadResHeader 將引發一個 EInvalidImage 異常事件。在 Classes 庫單元中也包含一個名為 ReadComponentRes 的函數,該函數執行相同的操作,只不過它基於應
用程序包含的資源建立自己的流。
8. ReadResHeader 方法
聲明: procedure ReadResHeader;
ReadResHeader 方法從流的當前位置讀取 Windows 資源文件頭,並將流的當前位置指針移到該文件頭的尾部。如果流不包含一個有效的資源文件頭, ReadResHeader 將引發一個 EInvalidImage 異常事件。
流的 ReadComponentRes 方法在從資源文件中讀取部件之前,會自動調用 ReadResHeader 方法,因此,通常程序員通常不需要自己調用它。
9. Seek 方法
聲明: function Seek(Offset: Longint; Origin: Word): Longint; virtual; abstract;
Seek 方法將流的當前指針移動 Offset 個字節,字節移動的起點由 Origin 指定。如果 Offset 是負數, Seek 方法將從所描述的起點往流的頭部移動。下表中列出了 Origin 的不同取值和它們的含義:
函數 Seek 的參數的取值
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
常量 值 Seek 的起點 Offset 的取值
─────────────────────────────────
SoFromBeginning 0 流的開頭 正 數
SoFromCurrent 1 流的當前位置 正數或負數
SoFromEnd 2 流的結尾 負 數
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10. Write 方法
在 Delphi 對象式管理的對象中有兩類對象的方法都有稱為 Write 的: Stream 對象和 Filer 對象。 Stream 對象的 Write 方法將數據寫進流中。 Filer 對象通過相關的流傳遞數據,在后文中會介紹這類方法。
Stream 對象的 Write 方法聲明如下:
function Write(const Buffer; Count: Longint): Longint; virtual; abstract;
Write 方法將 Buffer 中的 Count 個字節寫入流中,並將當前位置指針向流的尾部移動 Count 個字節,函數返回寫入的字節數。
TStream 的 Write 方法是抽象的,每個繼承的 Stream 對象都要通過覆蓋該方法來提供向特定存儲媒介 ( 內存、磁盤文件等 ) 寫數據的特定方法。流的其它所有寫數據的方法 ( 如 WriteBuffer 、 WriteComponent) 都調用 Write 擔當實際的寫操作。
11. WriteBuffer 方法
聲明: procedure WriteBuffer(const Buffer; Count: Longint);
WriteBuffer 的功能與 Write 相似。 WriteBuffer 方法調用 Write 來執行實際的寫操作,如果流沒能寫所有字節, WriteBuffer 會觸發一個 EWriteError 異常事件。
12. WriteComponent 方法
在 Stream 對象和 Filer 對象都有被稱為 WriteComponent 的方法。 Stream 對象的 WriteComponent 方法將 Instance 所指定的部件和它所包含的所有部件都寫入流中; Writer 對象的 WriteComponent 將指定部件的屬性值寫入 Writer 對象的流中。
Stream 對象的 WriteComponent 方法聲明是這樣的:
procedure WriteComponent(Instance: Tcomponent);
WriteComponent 創建一個 Writer 對象,並調用 Writer 的 WriteRootComponent 方法將 Instance 及其擁有的對象寫入流。
13. WriteComponentRes 方法
聲明: WriteComponentRes(const ResName: String; Instance: TComponent);
WriteComponentRes 方法首先往流中寫入標准 Windows 資源文件頭,然后將 Instance 指定的部件寫入流中。要讀由 WriteComponentRes 寫入的部件,必須調用 ReadComponentRes 方法。
WriteComponentRes 使用 ResName 傳入的字符串作為資源文件頭的資源名,然后調用 WriteComponent 方法將 Instance 和它擁有的部件寫入流。
14. WriteDescendant 方法
聲明: procedure WriteDescendant(Instance Ancestor: TComponent);
Stream 對象的 WriteDescendant 方法創建一個 Writer 對象,然后調入該對象的 WriteDescendant 方法將 Instance 部件寫入流中。 Instance 可以是從 Ancestor 部件繼承的窗體,也可以是在從祖先窗體中繼承的窗體中相應於祖先窗體中 Ancestor 部件的部件。
15. WriteDescendantRes 方法
聲明: procedure WriteDescendantRes(const ResName: String;
Instance, Ancestor: TComponent);
WriteDescendantRes 方法將 Windows 資源文件頭寫入流,並使用 ResName 作用資源名,然后調用 WriteDescendant 方法,將 Instance 寫入流。
TStream 的實現原理
TStream 對象是 Stream 對象的基礎類,這是 Stream 對象的基礎。為了能在不同媒介上的存儲數據對象,后繼的 Stream 對象主要是在 Read 和 Write 方法上做了改進,。因此,了解 TStream 是掌握 Stream 對象管理的核心。 Borland 公司雖然提供了 Stream 對象的接口說明文檔,但對於其實現和應
用方法卻沒有提及,筆者是從 Borland Delphi 2.0 Client/Server Suite 提供的源代碼和部分例子程序中掌握了流式對象技術。
下面就從 TStream 的屬性和方法的實現開始。
1. TStream 屬性的實現
前面介紹過, TStream 具有 Position 和 Size 兩個屬性,作為抽象數據類型,它抽象了在各種存儲媒介中讀寫數據所需要經常訪問的域。那么它們是怎樣實現的呢?
在自定義部件編寫這一章中介紹過部件屬性定義中的讀寫控制。 Position 和 Size 也作了讀寫控制。定義如下:
property Position: Longint read GetPosition write SetPosition;
property Size: Longint read GetSize;
由上可知, Position 是可讀寫屬性,而 Size 是只讀的。
Position 屬性的實現就體現在 GetPosition 和 SetPosition 。當在程序運行過程中,任何讀取 Position 的值和給 Position 賦值的操作都會自動觸發私有方法 GetPosition 和 SetPosition 。兩個方法的聲明如下:
function TStream.GetPosition: Longint;
begin
Result := Seek(0, 1);
end;
procedure TStream.SetPosition(Pos: Longint);
begin
Seek(Pos, 0);
end;
在設置位置時, Delphi 編譯機制會自動將 Position 傳為 Pos 。
前面介紹過 Seek 的使用方法,第一參數是移動偏移量,第二個參數是移動的起點,返回值是移動后的指針位置。
Size 屬性的實現只有讀控制,完全屏蔽了寫操作。讀控制方法 GetSize 實現如下:
function TStream.GetSize: Longint;
var
Pos: Longint;
begin
Pos := Seek(0, 1);
Result := Seek(0, 2);
Seek(Pos, 0);
end;
2. TStream 方法的實現
⑴ CopyFrom 方法
CopyFrom 是 Stream 對象中很有用的方法,它用於在不同存儲媒介中拷貝數據。例如,內存與外部文件之間、內存與數據庫字段之間等。它簡化了許多內存分配、文件打開和讀寫等的細節,將所有拷貝操作都統一到 Stream 對象上。
前面曾介紹: CopyFrom 方法帶 Source 和 Count 兩個參數並返回長整型。該方法將 Count 個字節的內容從 Source 拷貝到當前流中,如果 Count 值為 0 則拷貝所有數據。
function TStream.CopyFrom(Source: TStream; Count: Longint): Longint;
const
MaxBufSize = $F000;
var
BufSize, N: Integer;
Buffer: PChar;
begin
if Count = 0 then
begin
Source.Position := 0;
Count := Source.Size;
end;
Result := Count;
if Count > MaxBufSize then BufSize := MaxBufSize else BufSize := Count;
GetMem(Buffer, BufSize);
try
while Count <> 0 do
begin
if Count > BufSize then
N := BufSize
else
N := Count;
Source.ReadBuffer(Buffer^, N);
WriteBuffer(Buffer^, N);
Dec(Count, N);
end;
finally
FreeMem(Buffer, BufSize);
end;
end;
⑵ ReadBuffer 方法和 WriteBuffer 方法
ReadBuffer 方法和 WriteBuffer 方法簡單地調用虛擬函數 Read 、 Write 來讀寫流中數據,它比 Read 和 Write 增加了讀寫數據出錯時的異常處理。
procedure TStream.ReadBuffer(var Buffer; Count: Longint);
begin
if (Count <> 0) and (Read(Buffer, Count) <> Count) then
raise EReadError.CreateRes(SReadError);
end;
procedure TStream.WriteBuffer(const Buffer; Count: Longint);
begin
if (Count <> 0) and (Write(Buffer, Count) <> Count) then
raise EWriteError.CreateRes(SWriteError);
end;
⑶ ReadComponent 、 ReadResHeader 和 ReadComponentRes 方法
ReadComponent 方法從當前流中讀取部件。在實現上 ReadComponent 方法創建了一個 TStream 對象,並用 TReader 的 ReadRootComponent 方法讀部件。在 Delphi 對象式管理中, Stream 對象和 Filer 對象結合很緊密。 Stream 對象的許多方法的實現需要 Filer 對象的支持,而 Filer 對象的構造函數
直接就以 Stream 對象為參數。在 ReadComponent 方法的實現中就可清楚地看到這一點:
function TStream.ReadComponent(Instance: TComponent): TComponent;
var
Reader: TReader;
begin
Reader := TReader.Create(Self, 4096);
try
Result := Reader.ReadRootComponent(Instance);
finally
Reader.Free;
end;
end;
ReadResHeader 方法用於讀取 Windows 資源文件的文件頭,由 ReadComponentRes 方法在讀取 Windows 資源文件中的部件時調用,通常程序員不需自己調用。如果讀取的不是資源文件 ReadResH := FSize + Offset;
end;
Result := FPosition;
end;
Offse 代表移動的偏移量。 Origin 代表移動的起點,值為 0 表示從文件頭開始,值為 1 表示從當前位置開始,值為 2 表示從文件尾往前,這時 OffSet 一般為負數。 Seek 的實現沒有越界的判斷。
3. SaveToStream 和 SaveToFile 方法
SaveToStream 方法是將 MemoryStream 對象中的內容寫入 Stream 所指定的流。其實現如下:
procedure TCustomMemoryStream.SaveToStream(Stream: TStream);
begin
if FSize <> 0 then Stream.WriteBuffer(FMemory^, FSize);
end;
SaveToStream 方法調用了 Stream 的 WriteBuffer 方法,直接將 FMemory 中的內容按 FSize 字節長度寫入流中。
SaveToFile 方法是與 SaveToStream 方法相關的。 SaveToFile 方法首先創建了一個 FileStream 對象,然后把該文件 Stream 對象作為 SaveToStream 的參數,由 SaveToStream 方法執行寫操作,其實現如下:
procedure TCustomMemoryStream.SaveToFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream);
finally
Stream.Free;
end;
end;
在 Delphi 的許多對象的 SaveToStream 和 SaveToFile 、 LoadFromStream 和 LoadFromFile 方法的實現都有類似的嵌套結構。
TMemoryStream 對象
TMemoryStream 對象是一個管理動態內存中的數據的 Stream 對象,它是從 TCustomMemoryStream 中繼承下來的,除了從 TCustomMemoryStream 中繼承的屬性和方法外,它還增加和覆蓋了一些用於從磁盤文件和其它注台讀數據的方法。它還提供了寫入、消除內存內容的動態內存管理方法。下面
介紹它的這些屬性和方法。
TMemoryStream 的屬性和方法
1. Capacity 屬性
聲明: property Copacity: Longint;
Capacity 屬性決定了分配給內存流的內存池的大小。這與 Size 屬性有些不同。 Size 屬性是描述流中數據的大小。在程序中可以將 Capacity 的值設置的比數據所需最大內存大一些,這樣可以避免頻繁地重新分配。
2. Realloc 方法
聲明: function Realloc(var NewCapacity: Longint): Pointer; virtual;
Realloc 方法,以 8K 為單位分配動態內存,內存的大小由 NewCapacity 指定,函數返回指向所分配內存的指針。
3. SetSize 方法
SetSize 方法消除內存流中包含的數據,並將內存流中內存池的大小設為 Size 字節。如果 Size 為零,是 SetSize 方法將釋放已有的內存池,並將 Memory 屬性置為 nil ;否則, SetSize 方法將內存池大小調整為 Size 。
4. Clear 方法
聲明: procedure Clear;
Clear 方法釋放內存中的內存池,並將 Memory 屬性置為 nil 。在調用 Clear 方法后, Size 和 Position 屬性都為 0 。
5. LoadFromStream 方法
聲明: procedure LoadFromStream(Stream: TStream);
LoadFromStream 方法將 Stream 指定的流中的全部內容復制到 MemoryStream 中,復制過程將取代已有內容,使 MemoryStream 成為 Stream 的一份拷貝。
6. LoadFromFile 方法
聲明: procedure LoadFromFile(count FileName: String);
LoadFromFile 方法將 FileName 指定文件的所有內容復制到 MemoryStream 中,並取代已有內容。調用 LoadFromFile 方法后, MemoryStream 將成為文件內容在內存中的完整拷貝。
TMemoryStream 對象的實現原理
TMemoryStream 從 TCustomMemoryStream 對象直接繼承,因此可以享用 TCustomMemoryStream 的屬性和方法。前面講過, TCustomMemoryStream 是用於內存中數據操作的抽象對象,它為 MemoryStream 對象的實現提供了框架,框架中的內容還要由具體 MemoryStream 對象去填充。 TMemoryStrea
m 對象就是按動態內存管理的需要填充框架中的具體內容。下面介紹 TMemoryStream 對象的實 ? FBuffer := AllocMem(FDataSet.RecordSize);
FRecord := FBuffer;
if not FDataSet.GetCurrentRecord(FBuffer) then Exit;
OpenMode := dbiReadOnly;
end else
begin
if not (FDataSet.State in [dsEdit, dsInsert]) then DBError(SNotEditing);
OpenMode := dbiReadWrite;
end;
Check(DbiOpenBlob(FDataSet.Handle, FRecord, FFieldNo, OpenMode));
end;
FOpened := True;
if Mode = bmWrite then Truncate;
end;
該方法首先是用傳入的 Field 參數給 FField , FDataSet , FRecord 和 FFieldNo 賦值。方法中用 AllocMem 按當前記錄大小分配內存,並將指針賦給 FBuffer ,用 DataSet 部件的 GetCurrentRecord 方法,將記錄的值賦給 FBuffer ,但不包括 BLOB 數據。
方法中用到的 DbiOpenBlob 函數是 BDE 的 API 函數,該函數用於打開數據庫中的 BLOB 字段。
最后如果方法傳入的 Mode 參數值為 bmWrite ,就調用 Truncate 將當前位置指針以后的
數據刪除。
分析這段源程序不難知道:
● 讀寫 BLOB 字段,不允許 BLOB 字段所在 DataSet 部件有 Filter ,否則產生異常事件
● 要讀寫 BLOB 字段,必須將 DataSet 設為編輯或插入狀態
● 如果 BLOB 字段中的數據作了修改,則在創建 BLOB 流時,不再重新調用 DBiOpenBlob 函數,而只是簡單地將 FOpened 置為 True ,這樣可以用多個 BLOB 流對同一個 BLOB 字段讀寫
Destroy 方法釋放 BLOB 字段和為 FBuffer 分配的緩沖區,其實現如下:
destructor TBlobStream.Destroy;
begin
if FOpened then
begin
if FModified then FField.FModified := True;
if not FField.FModified then
DbiFreeBlob(FDataSet.Handle, FRecord, FFieldNo);
end;
if FBuffer <> nil then FreeMem(FBuffer, FDataSet.RecordSize);
if FModified then
try
FField.DataChanged;
except
Application.HandleException(Self);
end;
end;
如果 BLOB 流中的數據作了修改,就將 FField 的 FModified 置為 True ;如果 FField 的 Modified 為 False 就釋放 BLOB 字段,如果 FBuffer 不為空,則釋放臨時內存。最后根據 FModified 的值來決定是否啟動 FField 的事件處理過程 DataChanged 。
不難看出,如果 BLOB 字段作了修改就不釋放 BLOB 字段,並且對 BLOB 字段的修改只有到 Destroy 時才提交,這是因為讀寫 BLOB 字段時都避開了 FField ,而直接調用 BDE API 函數。這一點是在應用 BDE API 編程中很重要,即一定要修改相應數據庫部件的狀態。
2. Read 和 Write 方法的實現
Read 和 Write 方法都調用 BDE API 函數完成數據庫 BLOB 字段的讀寫,其實現如下:
function TBlobStream.Read(var Buffer; Count: Longint): Longint;
var
Status: DBIResult;
begin
Result := 0;
if FOpened then
begin
Status := DbiGetBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,
Count, @Buffer, Result);
case Status of
DBIERR_NONE, DBIERR_ENDOFBLOB:
begin
if FField.FTransliterate then
NativeToAnsiBuf(FDataSet.Locale, @Buffer, @Buffer, Result);
Inc(FPosition, Result);
end;
DBIERR_INVALIDBLOBOFFSET:
{Nothing};
else
DbiError(Status);
end;
end;
end;
Read 方法使用了 BDE
API 的 DbiGetBlob 函數從 FDataSet 中讀取數據,在本函數中,各參數的含義是這樣的: FDataSet.Handle 代表 DataSet 的 BDE 句柄, FReacord 表示 BLOB 字段所在記錄, FFieldNo 表示 BLOB 字段號, FPosition 表示要讀的的數據的起始位置, Count 表示要讀的字節數, Buffer 是讀出數據所占的內存,
Result 是實際讀出的字節數。該 BDE 函數返回函數調用的錯誤狀態信息。
Read 方法還調用了 NativeToAnsiBuf 進行字符集的轉換。
function TBlobStream.Write(const Buffer; Count: Longint): Longint;
var
Temp: Pointer;
begin
Result := 0;
if FOpened then
begin
if FField.FTransliterate then
begin
GetMem(Temp, Count);
try
AnsiToNativeBuf(FDataSet.Locale, @Buffer, Temp, Count);
Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,
Count, Temp));
finally
FreeMem(Temp, Count);
end;
end else
Check(DbiPutBlob(FDataSet.Handle, FRecord, FFieldNo, FPosition,
Count, @Buffer));
Inc(FPosition, Count);
Result := Count;
FModified := True;
end;
end;
Write 方法調用了 BDE API 的 DbiPutBlob 函數實現往數據庫 BLOB 字段存儲數據。
該函數的各參數含義如下:
調用函數 DbiPutBlob 的各傳入參數的含義
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
參數名 含義
──────────────────────────────
FDataSetHandle 寫入的數據庫的 BDE 句柄
FRecord 寫入數據的 BLOB 字段所在的記錄
FFieldNo BLOB 字段號
FPosition 寫入的起始位置
Count 寫入的數據的字節數
Buffer 所寫入的數據占有的內存地址
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
標志,該標志意味着后面存儲有一連串的項目。 Reader 對象,在讀這一連串項目時先調用 ReadListBegin 方法讀取該標志位,然后用 EndOfList 判斷是否列表結束,並用循環語句讀取項目。在調用 WriteListBegin 方法的后面必須調用 WriteListEnd 方法寫列表結束標志,相應的在 Reader 對象中
有 ReadListEnd 方法讀取該結束標志。
5. WriteListEnd 方法
聲明: procedure WriteListEnd;
WriteListEnd 方法在流中,寫入項目列表結束標志,它是與 WriteListBegin 相匹配的方法。
6. WriteBoolean 方法
聲明: procedure WriteBoolean(Value: Boolean);
WriteBoolean 方法將 Value 傳入的布爾值寫入流中。
7. WriteChar 方法
聲明: procedure WriteChar(Value: char);
WriteChar 方法將 Value 中的字符寫入流中。
8. WriteFloat 方法
聲明: procedure WriteFloat(Value: Extended);
WriteFloat 方法將 Value 傳入的浮點數寫入流中。
9. WriteInteger 方法
聲明: procedure WriteInteger(Value: Longint);
WriteInteger 方法將 Value 中的整數寫入流中。
10. WriteString 方法
聲明: procedure WriteString(const Value: string);
WriteString 方法將 Value 中的字符串寫入流中。
11. WriteIdent 方法
聲明: procedure WriteIdent(const Ident: string);
WriteIdent 方法將 Ident 傳入的標識符寫入流中。
12. WriteSignature 方法
聲明: procedure WriteSignature;
WriteSignature 方法將 Delphi Filer 對象標簽寫入流中。 WriteRootComponent 方法在將部件寫入流之前先調用 WriteSignature 方法寫入 Filer 標簽。 Reader 對象在讀部件之前調用 ReadSignature 方法讀取該標簽以指導讀操作。
13. WritComponent 方法
聲明: procedure WriteComponent(Component: TComponent);
WriteComponent 方法調用參數 Component 的 WriteState 方法將部件寫入流中。在調用 WriteState 之前, WriteComponent 還將 Component 的 ComponetnState 屬性置為 csWriting 。當 WriteState 返回時再清除 csWriting.
14. WriteRootComponent 方法
聲明: procedure WriteRootComponent(Root: TComponent);
WriteRootComponent 方法將 Writer 對象 Root 屬性設為參數 Root 帶的值,然后調用 WriteSignature 方法往流中寫入 Filer 對象標簽,最后調用 WriteComponent 方法在流中存儲 Root 部件。
