首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 第 20 章:開發物件導向資料管理功能(一)─ TMemoryStream 動態記憶體管理實作

     編輯:Delphi

20.1.5.2 TMemoryStream 實作原理深度剖析

TMemoryStream 直接繼承 TCustomMemoryStream,繼承其屬性與方法。TCustomMemoryStream 為記憶體資料操作的抽象類別,提供框架;TMemoryStream 依動態記憶體管理需求填充具體實作。

1. Capacity 屬性實作

TMemoryStream 在 protected 區新增 Capacity 屬性,決定記憶體串流佔用的動態記憶體大小。私有欄位 FCapacity 儲存屬性值,讀取直接回傳 FCapacity,寫入呼叫 SetCapacity:

property Capacity: Longint read FCapacity write SetCapacity;
procedure TMemoryStream.SetCapacity(NewCapacity: Longint);
begin
  SetPointer(Realloc(NewCapacity), FSize);
  FCapacity := NewCapacity;
end;

SetCapacity 先呼叫 Realloc 重新配置記憶體,再更新 FCapacity。Realloc 會處理物件狀態變更。

2. 核心方法實作

⑴ Realloc 方法:動態記憶體配置核心

const
  MemoryDelta = $2000; { 8K }

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;
  • 以 8K 為單位 配置記憶體(第一行 if 對齊邊界)。
  • NewCapacity = 0:釋放記憶體(GlobalFreePtr)。
  • 原 Capacity = 0:配置新記憶體(GlobalAllocPtr)。
  • 否則:重新配置記憶體(GlobalReallocPtr)。
  • 配置失敗(Result = nil)拋出 EStreamError。

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

若寫入位置超出目前記憶體池,呼叫 SetCapacity 擴充,再以 System.Move 複製資料,更新位置指標並回傳寫入位元組數。FCapacity(配置容量)與 FSize(實際資料大小)不同。

⑶ Clear 方法:清空記憶體流

procedure TMemoryStream.Clear;
begin
  SetCapacity(0);
  FSize := 0;
  FPosition := 0;
end;

釋放記憶體池,將 Memory 設為 nil,FSize 與 FPosition 歸零。

⑷ LoadFromStream 與 LoadFromFile 方法

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;

LoadFromStream:依來源串流 Size 重新配置記憶體,呼叫來源 ReadBuffer 複製全部內容,形成完整拷貝。

LoadFromFile:建立 TFileStream 後呼叫 LoadFromStream,將檔案內容完整複製到記憶體串流。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved