|
1、新编容器类(TLazMemTable)的原因
=========================
在开发完成QuickBurro for Lazarus 开发包并在Windows下测试通过之后,咱迫不及待地在WinCE/WM上对开发包进行了测试,但是,让人沮丧的事情发生了:Lazarus的标准数据集对象TMemDataset等竟然不能正常工作,读写记录、字段得到的结果是错误的! 大跌眼镜!
没办法,因为数据集容器对象是三层架构中最重要的对象之一,绝对不能少了——于是,就自己开写!
由于只是容器类、同时也是为了减小工作量,俺把目标放低了点: 新实现的容器类只要能以一种高效紧凑的格式容纳数据集、能方便地定义结构、读写记录、与流对象之间进行转换以便进行远程传输、移动记录指针等——就基本够用了,记录删除、检索、改表结构、数据感知之类,暂且不用支持,因为移动设备端无需大规模编程,不用数据感知之类的高级功能。
写了两天,调试后很快就测试通过了,然后,应用到QuickBurro for Lazarus 开发包中,最后,再基于这个类进行WinCE/WM下的编程测试——结果全线通过、效果令人满意。
2、容器类(TLazMemTable)的源码
=======================
//
//-------------------------------------------------------------------------
//
//
// QuickBurro Middleware Application Development Package for Lazarus
//
// Version 4.28
// Update Date: 2013.8.5.
// Author: Jopher(W.G.Z.)
// QQ: 779545524
// QQ groups: 79114999,33286656,116166458,84945607,18594635
// Email: Jopher@189.cn or wpy020327@163.com
// Homepage: http://www.quickburro.com/
//
// Copyright(C) Jopher Software Studio,2006-2013. All rights reserved
//
//
//-------------------------------------------------------------------------
//
unit LazMemTable;
interface
uses
SysUtils,
Classes,
LResources,
db;
type
TTableOpenEvent = procedure (Sender: TObject) of object;
TTableCloseEvent = procedure (Sender: TObject) of Object;
TLazMemTable=class(TComponent)
private
fActive: boolean;
fFieldCount: integer;
fRecordCount: integer;
fRecNo: integer;
fInAppend: boolean;
fInEdit: boolean;
fRecordSize: integer;
fOnTableOpened: TTableOpenEvent;
fOnTableClosed: TTableCloseEvent;
DataAreaLength: integer;
DataArea: array of byte;
procedure SetActive(aActive: boolean);
procedure SetRecNo(aRecNo: integer);
function DoOpen(): boolean;
function DoClose(): boolean;
public
Constructor Create(AOwner: TComponent); override;
Destructor Destroy(); override;
procedure Clear;
procedure ClearRecords;
procedure Open;
procedure Close;
function FindFieldDef(aFieldName: string): integer;
procedure AddFieldDef(FieldName: string; FieldType: TFieldType; FieldSize: integer);
procedure GetFieldDef(const aFieldIndex: integer; var FieldName: string; var FieldType: TFieldType; var FieldSize: integer); overload;
procedure GetFieldDef(const FieldName: string; var FieldIndex: integer; var FieldType: TFieldType; var FieldSize: integer); overload;
function GetAsString(const aFieldIndex: integer): string; overload;
function GetAsString(const aFieldName: string): string; overload;
function GetAsBoolean(const aFieldIndex: integer): Boolean; overload;
function GetAsBoolean(const aFieldName: string): Boolean; overload;
function GetAsInteger(const aFieldIndex: integer): Integer; overload;
function GetAsInteger(const aFieldName: string): Integer; overload;
function GetAsInt64(const aFieldIndex: integer): Int64; overload;
function GetAsInt64(const aFieldName: string): Int64; overload;
function GetAsSmallInt(const aFieldIndex: integer): SmallInt; overload;
function GetAsSmallInt(const aFieldName: string): SmallInt; overload;
function GetAsFloat(const aFieldIndex: integer): Double; overload;
function GetAsFloat(const aFieldName: string): Double; overload;
function GetAsDateTime(const aFieldIndex: integer): TDateTime; overload;
function GetAsDateTime(const aFieldName: string): TDateTime; overload;
function GetAsDate(const aFieldIndex: integer): TDateTime; overload;
function GetAsDate(const aFieldName: string): TDateTime; overload;
function GetAsTime(const aFieldIndex: integer): TDateTime; overload;
function GetAsTime(const aFieldName: string): TDateTime; overload;
function GetRecord(): string;
procedure Append;
procedure PutAsString(const aFieldIndex: integer; const aFieldValue: string); overload;
procedure PutAsString(const aFieldName: string; const aFieldValue: string); overload;
procedure PutAsBoolean(const aFieldIndex: integer; const aFieldValue: Boolean); overload;
procedure PutAsBoolean(const aFieldName: string; const aFieldValue: Boolean); overload;
procedure PutAsInteger(const aFieldIndex: integer; const aFieldValue: Integer); overload;
procedure PutAsInteger(const aFieldName: string; const aFieldValue: Integer); overload;
procedure PutAsInt64(const aFieldIndex: integer; const aFieldValue: Int64); overload;
procedure PutAsInt64(const aFieldName: string; const aFieldValue: Int64); overload;
procedure PutAsSmallInt(const aFieldIndex: integer; const aFieldValue: SmallInt); overload;
procedure PutAsSmallInt(const aFieldName: string; const aFieldValue: SmallInt); overload;
procedure PutAsFloat(const aFieldIndex: integer; const aFieldValue: Double); overload;
procedure PutAsFloat(const aFieldName: string; const aFieldValue: Double); overload;
procedure PutAsDateTime(const aFieldIndex: integer; const aFieldValue: TDateTime); overload;
procedure PutAsDateTime(const aFieldName: string; const aFieldValue: TDateTime); overload;
procedure PutAsDate(const aFieldIndex: integer; const aFieldValue: TDate); overload;
procedure PutAsDate(const aFieldName: string; const aFieldValue: TDate); overload;
procedure PutAsTime(const aFieldIndex: integer; const aFieldValue: TTime); overload;
procedure PutAsTime(const aFieldName: string; const aFieldValue: TTime); overload;
procedure PutRecord(RecData: string);
procedure Edit;
procedure Post;
procedure First;
procedure Last;
procedure Next;
procedure Prior;
procedure MoveBy(Distance: integer);
function Bof(): boolean;
function Eof(): boolean;
function LoadFromStream(aStream: TMemoryStream): boolean;
function SaveToStream(aStream: TMemoryStream): boolean;
function LoadFromFile(aFileName: string): boolean;
function SaveToFile(aFileName: string): boolean;
property FieldCount: integer read fFieldCount;
property RecordCount: integer read fRecordCount;
property InAppend: boolean read fInAppend;
property InEdit: boolean read fInEdit;
property RecordSize: integer read fRecordSize;
property BufferSize: integer read DataAreaLength;
published
property Active: boolean read fActive write SetActive;
property RecNo: integer read fRecNo write SetRecNo;
property OnTableOpened: TTableOpenEvent read fOnTableOpened write fOnTableOpened;
property OnTableClosed: TTableCloseEvent read fOnTableClosed write fOnTableClosed;
end;
procedure Register;
implementation
const
RecordSetOffset=12*1024;
FieldDefSize=40;
procedure Register;
begin
RegisterComponents('QuickBurro', [TLazMemTable]);
end;
Constructor TLazMemTable.Create(AOwner: TComponent);
begin
inherited create(aOwner);
fActive:=false;
fFieldCount:=0;
fRecordCount:=0;
fRecNo:=-1;
fInAppend:=false;
fInEdit:=false;
fRecordSize:=0;
DataAreaLength:=12*1024;
SetLength(DataArea,DataAreaLength);
end;
Destructor TLazMemTable.Destroy();
begin
DataAreaLength:=0;
SetLength(DataArea,DataAreaLength);
inherited Destroy;
end;
procedure TLazMemTable.SetActive(aActive: boolean);
begin
if fActive=aActive then
exit;
if aActive then
doclose
else
doopen;
end;
procedure TLazMemTable.SetRecNo(aRecNo: integer);
begin
if aRecNo<0 then
fRecNo:=-1
else
begin
if aRecNo>fRecordCount then
fRecNo:=fRecordCount
else
fRecNo:=aRecNo;
end;
end;
function TLazMemTable.DoOpen(): boolean;
begin
if fFieldCount<=0 then
result:=false
else
begin
fActive:=true;
result:=true;
if assigned(fOnTableOpened) then
fOnTableOpened(self);
end;
end;
function TLazMemTable.DoClose(): boolean;
begin
fActive:=false;
fFieldCount:=0;
fRecordCount:=0;
fRecNo:=-1;
fInAppend:=false;
fInEdit:=false;
fRecordSize:=0;
DataAreaLength:=12*1024;
SetLength(DataArea,DataAreaLength);
result:=true;
if assigned(fOnTableClosed) then
fOnTableClosed(self);
end;
procedure TLazMemTable.Clear;
begin
doclose;
end;
procedure TLazMemTable.ClearRecords;
begin
DataAreaLength:=12*1024;
SetLength(DataArea,DataAreaLength);
fRecordCount:=0;
fRecNo:=-1;
fInAppend:=false;
fInEdit:=false;
end;
procedure TLazMemTable.Open;
begin
if fActive then
exit;
doopen;
end;
procedure TLazMemTable.Close;
begin
if not fActive then
exit;
doclose;
end;
function TLazMemTable.FindFieldDef(aFieldName: string): integer;
var
i: integer;
tmpstr: string;
begin
result:=-1;
for i := 0 to fFieldCount-1 do
begin
tmpstr:=trim(string(copy(DataArea,RecordSetOffset-(i+1)*FieldDefSize,30)));
if stricomp(PAnsiChar(aFieldName),PAnsiChar(tmpstr))=0 then
begin
result:=i;
break;
end;
end;
end;
procedure TLazMemTable.AddFieldDef(FieldName: string; FieldType: TFieldType; FieldSize: integer);
var
ptr: pointer;
FldSize: integer;
begin
ptr:=@DataArea[RecordSetOffset-(fFieldCount+1)*FieldDefSize];
fillchar(ptr^,30,' ');
move(FieldName[1],ptr^,length(FieldName));
DataArea[RecordSetOffset-(fFieldCount+1)*FieldDefSize+30]:=ord(FieldType);
case FieldType of
ftString: FldSize:=FieldSize;
ftBoolean: FldSize:=Sizeof(Boolean);
ftInteger: FldSize:=Sizeof(Integer);
ftLargeInt: FldSize:=Sizeof(Int64);
ftSmallInt: FldSize:=Sizeof(SmallInt);
ftFloat: FldSize:=Sizeof(Double);
ftDateTime,ftDate,ftTime: FldSize:=Sizeof(TDateTime);
else
exit;
end;
ptr:=@DataArea[RecordSetOffset-(fFieldCount+1)*FieldDefSize+31];
move(FldSize,ptr^,4);
ptr:=@DataArea[RecordSetOffset-(fFieldCount+1)*FieldDefSize+35];
move(fRecordSize,ptr^,4);
inc(fFieldCount);
fRecordSize:=fRecordSize+FldSize;
end;
procedure TLazMemTable.GetFieldDef(const aFieldIndex: integer; var FieldName: string; var FieldType: TFieldType; var FieldSize: integer);
var
ptr: pointer;
begin
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize];
setlength(FieldName,30);
move(ptr^,FieldName[1],30);
fieldName:=trim(FieldName);
FieldType:=TFieldType(DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+30]);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
end;
procedure TLazMemTable.GetFieldDef(const FieldName: string; var FieldIndex: integer; var FieldType: TFieldType; var FieldSize: integer);
var
ptr: pointer;
begin
FieldIndex:=FindFieldDef(FieldName);
if FieldIndex<>-1 then
begin
FieldType:=TFieldType(DataArea[RecordSetOffset-(FieldIndex+1)*FieldDefSize+30]);
ptr:=@DataArea[RecordSetOffset-(FieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
end;
end;
function TLazMemTable.GetAsString(const aFieldIndex: integer): string;
var
ptr: pointer;
FieldSize,FieldOffset,i,NullBytes: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
begin
result:='';
exit;
end;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
NullBytes:=0;
for i:= FieldSize-1 to 0 do
begin
if DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset+i]=0 then
inc(NullBytes)
else
break;
end;
setlength(Result,fieldsize-nullbytes);
if fieldsize>nullbytes then
begin
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,Result[1],fieldsize-nullbytes);
end;
end;
function TLazMemTable.GetAsString(const aFieldName: string): string;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=''
else
result:=GetAsString(FieldIndex);
end;
function TLazMemTable.GetAsBoolean(const aFieldIndex: integer): Boolean;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
begin
result:=false;
exit;
end;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsBoolean(const aFieldName: string): Boolean;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=false
else
result:=GetAsBoolean(FieldIndex);
end;
function TLazMemTable.GetAsInteger(const aFieldIndex: integer): Integer;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
begin
result:=0;
exit;
end;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsInteger(const aFieldName: string): Integer;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=0
else
result:=GetAsInteger(FieldIndex);
end;
function TLazMemTable.GetAsInt64(const aFieldIndex: integer): Int64;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
begin
result:=0;
exit;
end;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsInt64(const aFieldName: string): Int64;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=0
else
result:=GetAsInt64(FieldIndex);
end;
function TLazMemTable.GetAsSmallInt(const aFieldIndex: integer): SmallInt;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
begin
result:=0;
exit;
end;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsSmallInt(const aFieldName: string): SmallInt;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=0
else
result:=GetAsSmallInt(FieldIndex);
end;
function TLazMemTable.GetAsFloat(const aFieldIndex: integer): Double;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
begin
result:=0;
exit;
end;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsFloat(const aFieldName: string): Double;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=0
else
result:=GetAsFloat(FieldIndex);
end;
function TLazMemTable.GetAsDateTime(const aFieldIndex: integer): TDateTime;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsDateTime(const aFieldName: string): TDateTime;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=0
else
result:=GetAsDateTime(FieldIndex);
end;
function TLazMemTable.GetAsDate(const aFieldIndex: integer): TDateTime;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsDate(const aFieldName: string): TDateTime;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=0
else
result:=GetAsDate(FieldIndex);
end;
function TLazMemTable.GetAsTime(const aFieldIndex: integer): TDateTime;
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if (fRecNo<0) or (fRecNo>=fRecordCount) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(ptr^,result,fieldsize);
end;
function TLazMemTable.GetAsTime(const aFieldName: string): TDateTime;
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex<0 then
result:=0
else
result:=GetAsTime(FieldIndex);
end;
function TLazMemTable.GetRecord(): string;
var
ptr: pointer;
begin
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo];
setlength(result,fRecordSize);
move(ptr^,result[1],fRecordSize);
end;
procedure TLazMemTable.Append;
begin
if not fActive then
exit;
if fInAppend or fInEdit then
exit;
if (RecordSetOffset+(fRecordCount+1)*fRecordSize)>DataAreaLength then
begin
DataAreaLength:=DataAreaLength+fRecordSize*100;
SetLength(DataArea,DataAreaLength);
end;
fRecNo:=fRecordCount;
inc(fRecordCount);
fInAppend:=true;
end;
procedure TLazMemTable.PutAsString(const aFieldIndex: integer; const aFieldValue: string);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
fillchar(ptr^,FieldSize,0);
if length(aFieldValue)>=FieldSize then
move(aFieldValue[1],ptr^,FieldSize)
else
move(aFieldValue[1],ptr^,length(aFieldValue));
end;
procedure TLazMemTable.PutAsString(const aFieldName: string; const aFieldValue: string);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsString(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsBoolean(const aFieldIndex: integer; const aFieldValue: Boolean);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(Boolean));
end;
procedure TLazMemTable.PutAsBoolean(const aFieldName: string; const aFieldValue: Boolean);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsBoolean(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsInteger(const aFieldIndex: integer; const aFieldValue: Integer);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(Integer));
end;
procedure TLazMemTable.PutAsInteger(const aFieldName: string; const aFieldValue: Integer);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsInteger(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsInt64(const aFieldIndex: integer; const aFieldValue: Int64);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(Int64));
end;
procedure TLazMemTable.PutAsInt64(const aFieldName: string; const aFieldValue: Int64);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsInt64(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsSmallInt(const aFieldIndex: integer; const aFieldValue: SmallInt);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(SmallInt));
end;
procedure TLazMemTable.PutAsSmallInt(const aFieldName: string; const aFieldValue: SmallInt);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsSmallInt(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsFloat(const aFieldIndex: integer; const aFieldValue: Double);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(Double));
end;
procedure TLazMemTable.PutAsFloat(const aFieldName: string; const aFieldValue: Double);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsFloat(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsDateTime(const aFieldIndex: integer; const aFieldValue: TDateTime);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(TDateTime));
end;
procedure TLazMemTable.PutAsDateTime(const aFieldName: string; const aFieldValue: TDateTime);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsDateTime(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsDate(const aFieldIndex: integer; const aFieldValue: TDate);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(TDate));
end;
procedure TLazMemTable.PutAsDate(const aFieldName: string; const aFieldValue: TDate);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsDate(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutAsTime(const aFieldIndex: integer; const aFieldValue: TTime);
var
ptr: pointer;
FieldSize,FieldOffset: integer;
begin
if not (fInAppend or fInEdit) then
exit;
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+31];
move(ptr^,FieldSize,4);
ptr:=@DataArea[RecordSetOffset-(aFieldIndex+1)*FieldDefSize+35];
move(ptr^,FieldOffset,4);
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo+FieldOffset];
move(aFieldValue,ptr^,Sizeof(TTime));
end;
procedure TLazMemTable.PutAsTime(const aFieldName: string; const aFieldValue: TTime);
var
FieldIndex: integer;
begin
FieldIndex:=FindFieldDef(aFieldName);
if FieldIndex>=0 then
PutAsTime(FieldIndex,aFieldValue);
end;
procedure TLazMemTable.PutRecord(RecData: string);
var
ptr: pointer;
begin
ptr:=@DataArea[RecordSetOffset+fRecordSize*fRecNo];
move(RecData[1],ptr^,fRecordSize);
end;
procedure TLazMemTable.Edit;
begin
if not fActive then
exit;
if fInAppend or fInEdit then
exit;
if (fRecNo<0) or (fRecNo>=fRecordCount) then
exit;
fInEdit:=true;
end;
procedure TLazMemTable.Post;
begin
if not (fInAppend or fInEdit) then
exit;
fInAppend:=false;
fInEdit:=false;
end;
procedure TLazMemTable.First;
begin
if (not fActive) or fInAppend or fInEdit then
exit;
if fRecordCount>0 then
fRecNo:=0
else
fRecNo:=-1;
end;
procedure TLazMemTable.Last;
begin
if (not fActive) or fInAppend or fInEdit then
exit;
if fRecordCount>0 then
fRecNo:=fRecordCount-1
else
fRecNo:=-1;
end;
procedure TLazMemTable.Next;
begin
if (not fActive) or fInAppend or fInEdit then
exit;
if (fRecordCount>0) and (fRecNo<fRecordCount) then
inc(fRecNo);
end;
procedure TLazMemTable.Prior;
begin
if (not fActive) or fInAppend or fInEdit then
exit;
if (fRecordCount>0) and (fRecNo>=0) then
dec(fRecNo);
end;
procedure TLazMemTable.MoveBy(Distance: integer);
begin
if (not fActive) or fInAppend or fInEdit then
exit;
if fRecNo+Distance<0 then
fRecNo:=-1
else
begin
if fRecNo+Distance>fRecordCount then
fRecNo:=fRecordCount
else
fRecNo:=fRecNo+Distance;
end;
end;
function TLazMemTable.Bof(): boolean;
begin
result:=(not fActive) or (fRecordCount=0) or (fRecNo<0);
end;
function TLazMemTable.Eof(): boolean;
begin
result:=(not fActive) or (fRecordCount=0) or (fRecNo>=fRecordCount);
end;
function TLazMemTable.LoadFromStream(aStream: TMemoryStream): boolean;
var
ptr: Pointer;
begin
aStream.Position:=0;
aStream.Read(fFieldCount,4);
aStream.Read(fRecordCount,4);
aStream.Read(fRecordSize,4);
if (fFieldCount<=0) or (fRecordCount<0) or (fRecordSize<=0)
or (aStream.Size<>(12+fFieldCount*FieldDefSize+fRecordCount*fRecordSize)) then
begin
result:=false;
exit;
end;
DataAreaLength:=RecordSetOffset+fRecordCount*fRecordSize;
setlength(DataArea,DataAreaLength);
ptr:=@DataArea[RecordSetOffset-fFieldCount*FieldDefSize];
aStream.Read(ptr^,fFieldCount*FieldDefSize+fRecordCount*fRecordSize);
fInAppend:=false;
fInEdit:=false;
if fRecordCount=0 then
fRecNo:=-1
else
fRecNo:=0;
fActive:=true;
if assigned(fOnTableOpened) then
fOnTableOpened(self);
result:=true;
end;
function TLazMemTable.SaveToStream(aStream: TMemoryStream): boolean;
var
ptr: Pointer;
begin
if not fActive then
begin
result:=false;
exit;
end;
aStream.Clear;
aStream.Write(fFieldCount,4);
aStream.Write(fRecordCount,4);
aStream.Write(fRecordSize,4);
ptr:=@DataArea[RecordSetOffset-fFieldCount*FieldDefSize];
aStream.Write(ptr^,fFieldCount*FieldDefSize+fRecordCount*fRecordSize);
result:=true;
end;
function TLazMemTable.LoadFromFile(aFileName: string): boolean;
var
Stream: TMemoryStream;
begin
Stream:=TMemoryStream.Create;
try
Stream.LoadFromFile(aFileName);
result:=LoadFromStream(stream);
except
result:=false;
end;
FreeAndNil(Stream);
end;
function TLazMemTable.SaveToFile(aFileName: string): boolean;
var
Stream: TMemoryStream;
begin
Stream:=TMemoryStream.Create;
try
result:=SaveToStream(stream);
if result then
begin
Stream.Position:=0;
Stream.SaveToFile(aFileName);
end;
except
result:=false;
end;
FreeAndNil(Stream);
end;
Initialization
{$i lazmemtable.lrs}
end.
3、容器类(TLazMemTable)的功能测试程序
============================
unit main;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
ComCtrls, LazMemTable, db;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button10: TButton;
Button11: TButton;
Button12: TButton;
Button13: TButton;
Button14: TButton;
Button15: TButton;
Button2: TButton;
Button3: TButton;
Button4: TButton;
Button5: TButton;
Button6: TButton;
Button7: TButton;
Button8: TButton;
Button9: TButton;
ImageList1: TImageList;
qbmt: TLazMemTable;
ListView1: TListView;
Memo1: TMemo;
procedure Button10Click(Sender: TObject);
procedure Button11Click(Sender: TObject);
procedure Button12Click(Sender: TObject);
procedure Button13Click(Sender: TObject);
procedure Button14Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure Button6Click(Sender: TObject);
procedure Button7Click(Sender: TObject);
procedure Button8Click(Sender: TObject);
procedure Button9Click(Sender: TObject);
procedure ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
procedure qbmtTableClosed(Sender: TObject);
procedure qbmtTableOpened(Sender: TObject);
procedure ShowTable;
procedure Button15Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
Stream: TMemoryStream;
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.ShowTable;
begin
if not qbmt.Active then
begin
listview1.Items.Clear;
exit;
end;
qbmt.First;
listview1.Items.BeginUpdate;
listview1.Items.Clear;
while not qbmt.Eof do
begin
with listview1.Items.Add do
begin
caption:=qbmt.GetAsString('CustomerId');
subitems.Add(qbmt.GetAsString('CustomerName'));
if qbmt.GetAsBoolean('IsPersonal') then
subitems.Add('是')
else
subitems.Add('否');
subitems.Add(inttostr(qbmt.GetAsInteger('age')));
subitems.Add(formatfloat('0.00',qbmt.GetAsFloat('height')));
subitems.Add(qbmt.GetAsString('Telephone'));
subitems.Add(formatDateTime('yyyy-mm-dd',qbmt.GetAsDateTime('CreateDate')));
imageindex:=0;
end;
qbmt.Next;
end;
listview1.Items.EndUpdate;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
qbmt.Append;
qbmt.PutAsString('CustomerId','13080001');
qbmt.PutAsString('CustomerName','杭州新时代媒体广告有限公司');
qbmt.PutAsBoolean('IsPersonal',false);
qbmt.PutAsInteger('Age',35);
qbmt.PutAsFloat('Height',175.5);
qbmt.PutAsString('Telephone','18912345678');
qbmt.PutAsDateTime('CreateDate',Now);
qbmt.Post;
//
qbmt.Append;
qbmt.PutAsString('CustomerId','13080002');
qbmt.PutAsString('CustomerName','上海新型材料有限公司');
qbmt.PutAsBoolean('IsPersonal',false);
qbmt.PutAsInteger('Age',42);
qbmt.PutAsFloat('Height',185.0);
qbmt.PutAsString('Telephone','1383838833');
qbmt.PutAsDateTime('CreateDate',Now);
qbmt.Post;
//
qbmt.Append;
qbmt.PutAsString('CustomerId','13080003');
qbmt.PutAsString('CustomerName','江苏省盐城市美声工作室');
qbmt.PutAsBoolean('IsPersonal',true);
qbmt.PutAsInteger('Age',41);
qbmt.PutAsFloat('Height',165.0);
qbmt.PutAsString('Telephone','15309878872');
qbmt.PutAsDateTime('CreateDate',Now);
qbmt.Post;
//
qbmt.Append;
qbmt.PutAsString('CustomerId','13080004');
qbmt.PutAsString('CustomerName','广东省韶关市墙体材料厂');
qbmt.PutAsBoolean('IsPersonal',false);
qbmt.PutAsInteger('Age',23);
qbmt.PutAsFloat('Height',175.0);
qbmt.PutAsString('Telephone','15302233422');
qbmt.PutAsDateTime('CreateDate',Now);
qbmt.Post;
//
showtable;
memo1.Lines.Add('追加4条记录成功!');
end;
procedure TForm1.Button12Click(Sender: TObject);
begin
qbmt.Clear;
showtable;
memo1.Lines.Add('清除所有表结构及记录成功!');
if qbmt.Active then
memo1.Lines.Add(' 内存表仍然处于打开状态!')
else
memo1.Lines.Add(' 内存表已处于关闭状态!');
end;
procedure TForm1.Button13Click(Sender: TObject);
begin
if qbmt.SaveToFile('c:\qbmt.dat') then
memo1.Lines.Add('导出到文件成功!')
else
memo1.Lines.Add('导出到文件失败!')
end;
procedure TForm1.Button14Click(Sender: TObject);
begin
if qbmt.LoadFromFile('c:\qbmt.dat') then
begin
showtable;
memo1.Lines.Add('从文件导入成功!');
end
else
memo1.Lines.Add('从文件导入失败!')
end;
procedure TForm1.Button10Click(Sender: TObject);
begin
qbmt.Next;
memo1.Lines.Add('指向下一记录成功!RecNo='+inttostr(qbmt.RecNo));
memo1.Lines.Add(' CustomerName='+qbmt.GetAsString('CustomerName'));
end;
procedure TForm1.Button11Click(Sender: TObject);
begin
qbmt.Last;
memo1.Lines.Add('转尾记录成功!RecNo='+inttostr(qbmt.RecNo));
memo1.Lines.Add(' CustomerName='+qbmt.GetAsString('CustomerName'));
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
qbmt.edit;
qbmt.PutAsString('CustomerName','北京市稀里糊涂市政建设有限公司');
qbmt.PutAsString('Telephone','18080808800');
qbmt.PutAsDateTime('CreateDate',Now);
qbmt.Post;
showtable;
memo1.Lines.Add('修改记录成功!');
end;
procedure TForm1.Button4Click(Sender: TObject);
begin
qbmt.Close;
listview1.Items.Clear;
memo1.Lines.Add('关闭数据表成功!');
if qbmt.Bof then
memo1.Lines.Add(' BOF=true')
else
memo1.Lines.Add(' BOF=false');
if qbmt.Eof then
memo1.Lines.Add(' EOF=true')
else
memo1.Lines.Add(' EOF=false');
end;
procedure TForm1.Button5Click(Sender: TObject);
begin
qbmt.ClearRecords;
showtable;
memo1.Lines.Add('清除所有记录成功!');
if qbmt.Active then
memo1.Lines.Add(' 内存表仍然处于打开状态!')
else
memo1.Lines.Add(' 内存表已处于关闭状态!');
end;
procedure TForm1.Button6Click(Sender: TObject);
begin
Stream:=TMemoryStream.Create;
memo1.Lines.Add('BufferSize='+inttostr(qbmt.bufferSize));
if qbmt.SaveToStream(stream) then
memo1.Lines.Add('导出到流对象成功!Stream.Size='+inttostr(Stream.Size))
else
memo1.Lines.Add('导出到流对象失败!');
end;
procedure TForm1.Button7Click(Sender: TObject);
begin
if qbmt.LoadFromStream(stream) then
begin
ShowTable;
memo1.Lines.Add('从流对象导入成功!');
end
else
memo1.Lines.Add('从流对象导入失败!');
memo1.Lines.Add('BufferSize='+inttostr(qbmt.bufferSize));
FreeAndNil(Stream);
end;
procedure TForm1.Button8Click(Sender: TObject);
begin
qbmt.First;
memo1.Lines.Add('转首记录成功!RecNo='+inttostr(qbmt.RecNo));
memo1.Lines.Add(' CustomerName='+qbmt.GetAsString('CustomerName'));
end;
procedure TForm1.Button9Click(Sender: TObject);
begin
qbmt.Prior;
memo1.Lines.Add('回退记录成功!RecNo='+inttostr(qbmt.RecNo));
memo1.Lines.Add(' CustomerName='+qbmt.GetAsString('CustomerName'));
end;
procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
Selected: Boolean);
begin
if listview1.Selected=nil then
exit;
qbmt.RecNo:=listview1.Selected.Index;
memo1.Lines.Add('定位记录成功!CustomerName='+qbmt.GetAsString('CustomerName'));
end;
procedure TForm1.qbmtTableClosed(Sender: TObject);
begin
memo1.Lines.Add('*** 内存表关闭事件激发!');
end;
procedure TForm1.qbmtTableOpened(Sender: TObject);
begin
memo1.Lines.Add('*** 内存表打开事件激发!');
end;
procedure TForm1.Button15Click(Sender: TObject);
begin
close;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
qbmt.AddFieldDef('CustomerId',ftString,8);
qbmt.AddFieldDef('CustomerName',ftString,48);
qbmt.AddFieldDef('IsPersonal',ftBoolean,0);
qbmt.AddFieldDef('Age',ftInteger,0);
qbmt.AddFieldDef('Height',ftFloat,0);
qbmt.AddFieldDef('Telephone',ftString,16);
qbmt.AddFieldDef('CreateDate',ftDateTime,0);
qbmt.Open;
if qbmt.Active then
memo1.Lines.Add('创建并打开内存表成功!')
else
memo1.Lines.Add('创建并打开内存表失败!');
memo1.Lines.Add(' FieldCount='+inttostr(qbmt.FieldCount)+' RecordCount='+inttostr(qbmt.RecordCount)+' RecordSize='+inttostr(qbmt.recordsize));
showtable;
end;
end.
|
|