Delphi的元件讀寫機制(一)
一、流式物件(Stream)和讀寫物件(Filer)的介紹
在物件導向程式設計中,物件式資料管理佔有很重要的地位。在Delphi中,對物件式資料管理的支援方式是其一大特色。
Delphi是一個物件導向的視覺化設計與物件導向的語言結合的整合開發環境。 Delphi的核心是元件。組件是物件的一種。 Delphi應用程式完全是由元件來建構的,因此開發高效能的Delphi應用程式必然會涉及物件式資料管理技術。
對象式資料管理包括兩方面的內容:
● 用物件來管理數據
● 對各類資料物件(包括物件和元件)的管理
Delphi將物件式資料管理類別歸結為Stream物件(Stream)和Filer物件(Filer),並將它們應用於視覺元件類別庫(VCL)的方方面面。它們提供了豐富的在記憶體、外存和Windows資源中管理物件的功能,
Stream對象,又稱流式對象,是TStream、THandleStream、TFileStream、TMemoryStream、TResourceStream和TBlobStream等的統稱。它們分別代表了在各種媒介上儲存資料的能力,它們將各種資料類型(包括物件和元件) 在記憶體、外存和資料庫欄位中的管理操作抽象化為物件方法,並且充分利用了物件導向技術的優點,應用程式可以相當容易地在各種Stream物件中拷貝資料。
讀寫物件(Filer)包括TFiler物件、TReader物件和TWriter物件。 TFiler物件是檔案讀寫的基礎對象,在應用程式中使用的主要是TReader和TWriter。 TReader和TWriter物件都直接從TFiler物件繼承。 TFiler物件定義了Filer物件的基本屬性和方法。
Filer物件主要完成兩大功能:
● 存取窗體檔案和窗體檔案中的元件
●提供資料緩衝,加快資料讀寫操作
為了對流式物件和讀寫物件有一個感性的認識,先來看一個例子。
a)寫文件
PRocedure TFomr1.WriteData (Sender: TObject); r;
Var
FileStream:TFilestream;
Mywriter:TWriter;
i: integer
Begin
FileStream:=TFilestream.create('c:/Test.txt',fmopenwrite);//建立檔案流對象
Mywriter:=TWriter.create(FileStream,1024); //把Mywriter和FileStream連結起來
Mywriter. writelistbegin; //寫入清單開始標誌
For i:=0 to Memo1.lines.count-1 do
Mywriter.writestring(memo1.lines[i]); //儲存Memo元件中文字資訊到檔案中
Mywriter.writelistend; //寫入清單結束標誌
FileStream.seek(0,sofrombeginning); //檔案流物件指標移到流起始位置
Mywriter.free; //釋放Mywriter對象
FileStream.free; //釋放FileStream對象
End;
b)讀文件
procedure TForm1.ReadData(Sender: TObject);
Var
FileStream:TFilestream;
Myreader:TReader;
Begin
FileStream:=TFilestream.create('c:/Test.txt',fmopenread);
Myreader:=TRreader.create(FileStream,1024); //把Myreader和FileStream連結起來
Myreader.readlistbegin; //把寫入的清單開始標誌讀出來
Memo1.lines.clear; //清除Memo1元件的文字內容
While not myreader.endoflist do //注意TReader的一個方法:endoflist
Begin
Memo1.lines.add(myreader.readstring); //把讀出的字串加到Memo1元件中
End;
Myreader.readlistend; //把寫入的清單結束標誌讀出來
Myreader.free; //釋放Myreader對象
FileStream.free; //釋放FileStream對象
End;
上面兩個過程,一個為寫過程,一個為讀過程。寫入過程透過TWriter,利用TFilestream把一個Memo中的內容(文字訊息)存為一個儲存在磁碟上的二進位。讀取過程剛好和寫入過程相反,透過TReader,利用TFilestream把二進位檔案中的內容轉換為文字訊息並顯示在Memo中。執行程式可以看到,讀取過程中忠實的把寫過程所保存的資訊進行了還原。
下圖描述了資料物件(包括物件和元件)、串流物件和讀寫物件之間的關係。
圖(一)
值得注意的是,讀寫物件如TFiler物件、TReader物件和TWriter物件等很少由應用程式編寫者進行直接的調用,它通常用來讀寫元件的狀態,它在讀寫元件機制中扮演非常重要的角色。
對於串流物件Stream,許多參考資料上都有很詳細的介紹,而TFiler物件、TReader物件和TWriter物件特別是元件讀寫機制的參考資料則很少見,本文將透過對VCL原始程式碼的追蹤而對組件讀寫機制進行剖析。
二、讀寫物件(Filer)與元件讀寫機制
Filer物件主要用於存取Delphi的窗體檔案和窗體檔案中的元件,所以要清楚理解Filer物件就要清楚Delphi 窗體檔案(DFM檔案)的結構。
DFM檔案是用於Delphi儲存窗體的。窗體是Delphi可視化程式設計的核心。窗體對應Delphi應用程式中的窗口,窗體中的視覺元件對應視窗中的介面元素,非視覺元件如TTimer和TOpenDialog,對應Delphi應用程式的某項功能。 Delphi應用程式的設計實際上是以窗體的設計為中心。因此,DFM檔案在Delphi應用設計中也佔很重要的位置。窗體中的所有元素包括窗體本身的屬性都包含在DFM檔案中。
在Delphi應用程式視窗中,介面元素是按擁有關係相互聯繫的,因此樹狀結構是最自然的表達形式;相應地,窗體中的元件也是按樹狀結構組織;對應在DFM檔案中,也要表達這種關係。 DFM檔案在物理上,是以文字方式儲存的(在Delphi2.0版本以前是儲存為二進位檔案的),在邏輯上則是以樹狀結構安排各元件的關係。從該文本可以看清窗體的樹狀結構。下面是DFM檔案的內容:
object Form1: TForm1
Left = 197
Top = 124
……
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 272
……
Caption = 'Button1'
TabOrder = 0
end
object Panel1: TPanel
Left = 120
……
Caption = 'Panel1'
TabOrder = 1
object CheckBox1: TCheckBox
Left = 104
……
圖說 = 'CheckBox1'
TabOrder = 0
end
end
end
這個DFM檔案就是TWriter透過串流物件Stream來產生的,當然這裡還有一個二進位檔案到文字訊息檔案的轉換過程,這個轉換過程不是本文要研究的對象,所以忽略這樣的一個過程。
在程式開始運作的時候,TReader透過串流物件Stream來讀取窗體及元件,因為Delphi在編譯程式的時候,利用編譯指令{$R *.dfm}已經把DFM檔案資訊編譯到執行檔中,因此TReader讀取的內容實際上是被編譯到可執行檔中的有關窗體和元件的資訊。
TReader和TWriter不僅能夠讀取和寫入Object Pascal中絕大部分標準資料類型,而且能夠讀寫List、Variant等高階類型,甚至能夠讀寫Perperties和Component。不過,TReader、TWriter本身實際上提供的功能很有限,大部分的實際工作都是由TStream這個非常強大的類別來完成的。也就是說TReader、TWriter其實只是一個工具,它只是負責怎麼去讀寫元件,至於具體的讀寫操作是由TStream來完成的。
由於TFiler是TReader和TWriter的公共祖先類,因為要了解TReader和TWriter,還是先從TFiler開始。