流操作的語法 選擇自 cscer 的 Blog

 

流操作的語法

 

Delphi在這兩方面都做的相當出色。在Delphi的早期版本Turbo Pascal 中就曾有流(Stream)、羣(Collection)和資源(Resource)等專門用於對象式數據管理的類。在Delphi中,這些功能得到了大大的加強。Delphi將對象式數據管理類歸結爲Stream對象(Stream)和Filer對象(Filer),並將它們應用於可視部件類庫(VCL)的方方面面。它們不僅提供了在內存、外存和Windows資源中管理對象的功能,還提供了在數據庫BLOB字段中對象的功能。

  在本章中將介紹Stream對象和Filer對象的實現原理、應用方法以及在超媒體系統中的應用。這對於運用Delphi 開發高級應用是很重要的。 

20.1 流式對象的實現原理和應用

 

  Stream對象,又稱流式對象,是TStream、THandleStream、TFileStream、TMemoryStream、TResourceStream和TBlobStream等的統稱。它們分別代表了在各種媒介上存儲數據的能力,它們將各種數據類型(包括對象和部件) 在內存、外存和數據庫字段中的管理操作抽象爲對象方法,並且充分利用了面向對象技術的優點,應用程序可以相當容易地在各種Stream對象中拷貝數據。

  下面介紹各種對象的數據和方法及使用方法。

 

20.1.1 TStream對象

 

  TStream對象是能在各種媒介中存儲二進制數據的對象的抽象對象。從TStream 對象繼承的對象用於在內存、Windows資源文件、磁盤文件和數據庫字段等媒介中存儲數據。

  TStream中定義了兩個屬性:Size和Position。它們分別以字節爲單位表示的流的大小和當前指針位置。TStream中定義的方法用於在各種流中讀、寫和相互拷貝二進制數據。因爲所有的Stream對象都是從TStream中繼承來的,所以在TStream中定義的域和方法都能被Stream對象調用和訪問。此外,又由於面向對象技術的動態聯編功能,TStream爲各種流的應用提供了統一的接口,簡化了流的使用;不同Stream對象是抽象了對不同存儲媒介的數據上的操作,因此,TStream的需方法爲在不同媒介間的數據拷貝提供了最簡捷的手段。

 

20.1.1.1 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的不同取值和它們的含義:

 

表20.1 函數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寫入流。

 

20.1.1.2 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;

CouNG="ZH-CN">資源文件中的部件時調用,通常程序員不需自己調用。如果讀取的不是資源文件ReadResHeader,將觸發異常事件。

 

procedure TStream.ReadResHeader;

var

ReadCount: Longint;

Header: array[0..79] of Char;

begin

FillChar(Header, SizeOf(Header), 0);

ReadCount := Read(Header, SizeOf(Header) - 1);

if (Byte((@Header[0])^) = $FF) and (Word((@Header[1])^) = 10) then

Seek(StrLen(Header + 3) + 10 - ReadCount, 1)

else

raise EInvalidImage.CreateRes(SInvalidImage);

end;

 

  ReadComponentRes在Windows資源文件中讀取部件,爲了判斷是否是資源文件,它首先調用ReadResHeader方法,然後調用ReadComponent方法讀取Instance指定的部件。下面是它的實現:

 

function TStream.ReadComponentRes(Instance: TComponent): TComponent;

begin

ReadResHeader;

Result := ReadComponent(Instance);

end;

 

 與ReadComponentRes相應的寫方法是WriteComponentRes,Delphi 調用這兩個方法讀寫窗體文件(DFM文件),在後面書中會舉用這兩個方法讀取DFM文件的例子。

  ⑷ WriteComponent和WriteDescendant方法

  Stream對象的WriteDescendant方法在實現過程中,創建了TWriter對象,然後利用TWriter的WriteDescendant方法將Instance寫入流。而WriteComponent方法只是簡單地調用WriteDescendant方法將Instance寫入流。它們的實現如下:

  

procedure TStream.WriteComponent(Instance: TComponent);

begin

WriteDescendent(Instance, nil);

end;

 

procedure TStream.WriteDescendent(Instance, Ancestor: TComponent);

var

Writer: TWriter;

begin

Writer := TWriter.Create(Self, 4096);

try

Writer.WriteDescendent(Instance, Ancestor);

finally

Writer.Free;

end;

end;

 

  ⑸ WriteDescendantRes和WriteComponentRes方法

  WriteDescendantRes方法用於將部件寫入Windows資源文件;而WriteComponentRes 方法只是簡單地調用WriteDescendantRes方法,它們的實現如下:

 

procedure TStream.WriteComponentRes(const ResName: string; Instance:

TComponent);

begin

WriteDescendentRes(ResName, Instance, nil);

end;

 

procedure TStream.WriteDescendentRes(const ResName: string; Instance,

Ancestor: TComponent);

var

HeaderSize: Integer;

Origin, ImageSize: Longint;

Header: array[0..79] of Char;

begin

Byte((@Header[0])^) := $FF;

Word((@Header[1])^) := 10;

HeaderSize := StrLen(StrUpper(StrPLCopy(@Header[3], ResName, 63))) + 10;

Word((@Header[HeaderSize - 6])^) := $1030;

Longint((@Header[HeaderSize - 4])^) := 0;

WriteBuffer(Header, HeaderSize);

Origin := Position;

WriteDescendent(Instance, Ancestor);

ImageSize := Position - Origin;

Position := Origin - 4;

WriteBuffer(ImageSize, SizeOf(Longint));

Position := Origin + ImageSize;

end;

 

  WriteCompnentRes是與ReadComponentRes相應的對象寫方法,這兩個方法相互配合可讀取Delphi的DFM文件,從而利用Delphi系統的功能。

 

20.1.2 THandleStream對象

 

  THandleStream對象的行爲特別象FileStream對象,所不同的是它通過已創建的文件句柄而不是文件名來存儲流中的數據。

  THandleStream對象定義了Handle屬性,該屬性提供了對文件句柄的只讀訪問,並且Handle屬性可以作爲Delphi的RTL文件管理函數的參數,利用文件類函數來讀寫數據。THandleStream覆蓋了構造函數Create,該函數帶有Handle 參數,該參數指定與THandleStream對象相關的文件句柄。

 

20.1.2.1 THandleStream的屬性的方法:

 

  1. Handle屬性

  聲明:property Handle: Integer;

Handle屬性提供了對文件句柄的只讀訪問,該句柄由THandleStream的構造方法Create傳入。因此除了用THandleStream提供的方法外,也可以用文件管理函數對句柄進行操作。實際上,THandleStream的方法在實現上也是運用文件管理函數進行實際的讀寫操作。

  2. Create方法

  聲明:constructor Create(AHandle: Integer);

  Create方法使用傳入的Handle參數創建一個與特定文件句柄相聯的THandleStream對象,並且將AHandle賦給流的Handle屬性。

 

  3. Read、Write和Seek方法

  這三個方法是TStream的虛方法,只是在THandleStream 中覆蓋了這三個方法,以實現特定媒介──文件的數據存取。後面會詳細介紹這三個方法的實現。

 

20.1.2.2 THandleStream的實現原理

 

  THandleStream是從TStream繼承來的,因此可以共用TStream中的屬性和大多數方法。THandleStream在實現上主要是增加了一個屬性Handle和覆蓋了Create、Read、Write和Seek四個方法。

  1. 屬性的實現

  Handle屬性的實現正如Delphi大多數屬性的實現那樣,先在對象定義的private部分聲明一個存放數據的變量FHandle,然後在定義的public部分聲明屬性Handle,其中屬性定義的讀寫控制部分加上只讀控制,讀控制只是直接讀取FHandle變量的值,其實現如下:

 

THandleStream = class(TStream)

private

FHandle: Integer;

public

property Handle: Integer read FHandle;

end;

 

2. 方法的實現

  THandleStream的Create方法,以AHandle作爲參數,在方法裏面只是簡單的將AHandle的值賦給FHandle,其實現如下:

 

constructor THandleStream.Create(AHandle: Integer);

begin

FHandle := AHandle;

end;

 

  爲實現針對文件的數據對象存儲,THandleStream的Read、Write和Seek方法覆蓋了TStream中的相應方法。它們的實現都調用了Windows的文件管理函數。

  Read方法調用FileRead函數實現文件讀操作,其實現如下:

 

function THandleStream.Read(var Buffer; Count: Longint): Longint;

begin

Result := FileRead(FHandle, Buffer, Count);

if Result = -1 then Result := 0;

end;

 

  Write方法調用FileWrite函數實現文件寫操作,其實現如下:

 

function THandleStream.Write(const Buffer; Count: Longint): Longint;

begin

Result := FileWrite(FHandle, Buffer, Count);

if Result = -1 then Result := 0;

end;

 

  Seek方法調用FileSeek函數實現文件指針的移動,其實現如下:

 

function THandleStream.Seek(Offset: Longint; Origin: Word): Longint;

begin

Result := FileSeek(FHandle, Offset, Origin);

end;

 

20.1.3 TFileStream對象

 

  TFileStream對象是在磁盤文件上存儲數據的Stream對象。TFileStream是從THandleStream繼承下來的,它和THandleStream一樣都是實現文件的存取操作。不同之處在於THandleStream用句柄訪問文件,而TFileStream用文件名訪問文件。實際上TFileStream是THandleStream上的一層包裝,其內核是THandleStream的屬性和方法。

  TFileStream中沒有增加新的屬性和方法。它只是覆蓋了的構造方法Create和析構方法Destory。在Create方法中帶兩個參數FileName和Mode。FileName描述要創建或打開的文件名,而Mode描述文件模式如fmCreate、fmOpenRead和fmOpenWrite等。Create方法首先使用FileCreate或FileOpen函數創建或打開名爲FileName的文件,再將得到的文件句柄賦給FHandle。TFileStream的文件讀寫操作都是由從THandleStream繼承的Read

var

Stream: TStream;

begin

Stream := TFileStream.Create(FileName, fmCreate);

try

SaveToStream(Stream);

finally

Stream.Free;

end;

end;

 

  在Delphi 的許多對象的SaveToStream 和SaveToFile、LoadFromStream和LoadFromFile方法的實現都有類似的嵌套結構。

 

20.1.5 TMemoryStream對象

 

  TMemoryStream對象是一個管理動態內存中的數據的Stream對象,它是從TCustomMemoryStream中繼承下來的,除了從TCustomMemoryStream中繼承的屬性和方法外,它還增加和覆蓋了一些用於從磁盤文件和其它注臺讀數據的方法。它還提供了寫入、消除內存內容的動態內存管理方法。下面介紹它的這些屬性和方法。

 

20.1.5.1 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將成爲文件內容在內存中的完整拷貝。

 

20.1.5.2 TMemoryStream對象的實現原理

 

  TMemoryStream從TCustomMemoryStream對象直接繼承,因此可以享用TCustomMemoryStream的屬性和方法。前面講過,TCustomMemoryStream是用於內存中數據操作的抽象對象,它爲MemoryStream對象的實現提供了框架,框架中的內容還要由具體MemoryStream對象去填充。TMemoryStream對象就是按動態內存管理的需要填充框架中的具體內容。下面介紹TMemoryStream對象的實現。

  1. TMemoryStream屬性的實現

  TMemoryStream在其protected部分增加了一個Capacity屬性,該屬性決定了MemoryStream所佔動態內存的大小。TMemoryStream首先在private部分聲明瞭FCapacity變量作爲存儲Capacity屬性值的數據域,然後在protected部分聲明瞭該屬性。在屬性聲明的讀控制部分簡單讀取FCapacity的值,在寫控制處調用了方法SetCapacity。該方法除了給FCapacity賦值外還執行了修改Capacity屬性所必需操作如狀態改變等。

  下面是屬性的實現:

 

TMemoryStream = class(TCustomMemoryStream)

private

FCapacity: Longint;

procedure SetCapacity(NewCapacity: Longint);

protected

property Capacity: Longint read FCapacity write SetCapacity;

public

end;

 

  寫控制方法SetCapacity的實現是這樣的:

 

procedure TMemoryStream.SetCapacity(NewCapacity: Longint);

begin

SetPointer(Realloc(NewCapacity), FSize);

FCapacity := NewCapacity;

end;

 

  在SetCapacity 方法先是調用Realloc重新分配內存,然後用NewCapacity的值給FCapacity賦值。Realloc方法進行某些對象狀態的改變。

  2. TMemoryStream對象方法的實現

  ⑴ Realloc方法

  Realloc方法是TMemoryStream動態內存分配的核心,它的SetSize、SetCapacity等方法最終都是調用Realloc進行內存的分配和初始化工作的。它的實現如下:

 

const

MemoryDelta = $2000;

 

function TMemoryStream.Realloc(var NewCapacity: Longint): Pointer;

begin

if NewCapacity > 0 then

NewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1);

Result := Memory;

if NewCapacity <> FCapacity then

begin

if NewCapacity = 0 then

begin

GlobalFreePtr(Memory);

Result := nil;

end else

begin

if Capacity = 0 then

Result := GlobalAllocPtr(HeapAllocFlags, NewCapacity)

else

Result := GlobalReallocPtr(Memory, NewCapacity, HeapAllocFlags);

if Result = nil then raise EStreamError.CreateRes(SMemoryStreamError);

end;

end;

end;

 

  Realloc方法是以8K爲單位分配動態內存的,方法中的第一句if語句就是執行該操作。如果傳入的NewCapacity參數值爲0,則釋放流中的內存。Realloc方法用GLobal FreePtr函數釋放內存,用GlobalAllocPtr分配內存,用GlobalReallocPtr進行內存的重分配。如果原來的Capacity屬性值爲0,則調用Globa|AllocPtr否則調用GlobalReallocPtr。最後如果Result爲nil則觸發內存流錯的異常事件,否則返回指向分配的內存的指針。

  ⑵ Write方法

  Write方法從內存流內部緩衝池的當前位置開始寫入二進制數據。其實現如下:

 

function TMemoryStream.Write(const Buffer; Count: Longint): Longint;

var

Pos: Longint;

begin

if (FPosition >= 0) and (Count >= 0) then

begin

Pos := FPosition + Count;

if Pos > 0 then

begin

if Pos > FSize then

begin

if Pos > FCapacity then

SetCapacity(Pos);

FSize := Pos;

end;

System.Move(Buffer, Pointer(Longint(FMemory) + FPosition)^, Count);

FPosition := Pos;

Result := Count;

Exit;

end;

end;

Result := 0;

end;

 

  Buffer中存儲要寫入流的二進制數據,如果要寫入的數據的字節超出了流的內存池的大小,則調用SetCapacity方法再分配內存,然後用內存複製函數將Buffer中的數據複製到FMemory中。接着移動位置指針,並返回寫入數據的字節數。分析這段程序可以知道,FCapacity的值和FSize的值是不同的。

  ⑶ Clear方法

  Clear方法消除內存流中的數據,將Memory屬性置爲nil,並將FSize和FPosition 的值設爲0。其實現如下:

 

procedure TMemoryStream.Clear;

begin

SetCapacity(0);

FSize := 0;

FPosition := 0;

end;

 

  ⑷ LoadFromStream和LoadFromFile方法

  LoadFromStream方法首先根據傳入的Stream的Size屬性值重新分配動態內存,然後調用Stream的ReadBuffer方法往FMemory中複製數據,結果Stream的全部內容在內存中有了一份完整拷貝。其實現如下:

 

procedure TMemoryStream.LoadFromStream(Stream: TStream);

var

Count: Longint;

begin

Stream.Position := 0;

Count := Stream.Size;

SetSize(Count);

if Count <> 0 then Stream.ReadBuffer(FMemory^, Count);

end; 

  LoadFromFile與LoadFromStream是一對方法。LoadFromFile首先創建了一個TFileStream對象,然後調用LoadFromStream方法,將FileStream文件流中的數據寫入MemoryStream中。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章