首页 / 软件开发 / Delphi / 第二十章-开发Delphi对象式数据管理功能(一)(4)
第二十章-开发Delphi对象式数据管理功能(一)(4)2007-05-0720.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)privateFCapacity: Longint;procedure SetCapacity(NewCapacity: Longint);protected…property Capacity: Longint read FCapacity write SetCapacity;public…end;写控制方法SetCapacity的实现是这样的:procedure TMemoryStream.SetCapacity(NewCapacity: Longint);beginSetPointer(Realloc(NewCapacity), FSize);FCapacity := NewCapacity;end;在SetCapacity 方法先是调用Realloc重新分配内存,然后用NewCapacity的值给FCapacity赋值。Realloc方法进行某些对象状态的改变。2. TMemoryStream对象方法的实现⑴ Realloc方法Realloc方法是TMemoryStream动态内存分配的核心,它的SetSize、SetCapacity等方法最终都是调用Realloc进行内存的分配和初始化工作的。它的实现如下:constMemoryDelta = $2000; function TMemoryStream.Realloc(var NewCapacity: Longint): Pointer;beginif NewCapacity > 0 thenNewCapacity := (NewCapacity + (MemoryDelta - 1)) and not (MemoryDelta - 1);Result := Memory;if NewCapacity <> FCapacity thenbeginif NewCapacity = 0 thenbeginGlobalFreePtr(Memory);Result := nil;end elsebeginif Capacity = 0 thenResult := GlobalAllocPtr(HeapAllocFlags, NewCapacity)elseResult := 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;varPos: Longint;beginif (FPosition >= 0) and (Count >= 0) thenbeginPos := FPosition + Count;if Pos > 0 thenbeginif Pos > FSize thenbeginif Pos > FCapacity thenSetCapacity(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;beginSetCapacity(0);FSize := 0;FPosition := 0;end;⑷ LoadFromStream和LoadFromFile方法LoadFromStream方法首先根据传入的Stream的Size属性值重新分配动态内存,然后调用Stream的ReadBuffer方法往FMemory中复制数据,结果Stream的全部内容在内存中有了一份完整拷贝。其实现如下:procedure TMemoryStream.LoadFromStream(Stream: TStream);varCount: Longint;beginStream.Position := 0;Count := Stream.Size;SetSize(Count);if Count <> 0 then Stream.ReadBuffer(FMemory^, Count);end; LoadFromFile与LoadFromStream是一对方法。LoadFromFile首先创建了一个TFileStream对象,然后调用LoadFromStream方法,将FileStream文件流中的数据写入MemoryStream中。