程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> 第二十章-開發Delphi對象式數據管理功能(一)(4)

第二十章-開發Delphi對象式數據管理功能(一)(4)

編輯:Delphi

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中。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved