📄 kbmmemcsvstreamformat.pas
字号:
FreeMem(buf);
{$ENDIF}
inherited;
end;
procedure TkbmCustomCSVStreamFormat.DetermineLoadFieldIDs(ADataset:TkbmCustomMemTable; AList:TStringList; Situation:TkbmDetermineLoadFieldsSituation);
var
s:string;
null:boolean;
begin
// Dont try to get fields display names if def not yet loaded.
if (Situation<>dlfAfterLoadDef) or (Line='') or (sfLoadNoHeader in sfNoHeader) then
begin
inherited;
exit;
end;
// Determine which fields is present in the stream.
// Line has already been populated by LoadDef.
AList.Clear;
{$IFDEF DOTNET}
if assigned (backPtr) then Marshal.FreeHGlobal(BackPtr);
lptr:=Marshal.StringToHGlobalANSI(Line);
backPtr:=lptr;
try
elptr:=IntPtr(integer(lptr)+length(Line));
while (integer(lptr)<integer(elptr)) do
begin
// Get DisplayName for field.
s:=GetWord(null);
AList.Add(s);
end;
finally
Marshal.FreeHGlobal(BackPtr);
BackPtr:=nil;
end;
{$ELSE}
lptr:=PChar(Line);
while (lptr<elptr) do
begin
// Get DisplayName for field.
s:=GetWord(null);
AList.Add(s);
end;
{$ENDIF}
end;
procedure TkbmCUstomCSVStreamFormat.DetermineLoadFieldIndex(ADataset:TkbmCustomMemTable; ID:string; FieldCount:integer; OrigIndex:integer; var NewIndex:integer; Situation:TkbmDetermineLoadFieldsSituation);
var
i:integer;
s:string;
begin
// If determined not to load field, dont.
if (Situation<>dlfAfterLoadDef) then exit;
// Dont want to worry about case.
s:=UpperCase(ID);
// Find Field index in dataset
for i:=0 to ADataset.FieldCount-1 do
begin
if (UpperCase(ADataset.Fields[i].DisplayName)=s) then
begin
NewIndex:=i;
exit;
end;
end;
NewIndex:=-1;
end;
procedure TkbmCustomCSVStreamFormat.LoadDef(ADataset:TkbmCustomMemTable);
var
ld,ldidx:boolean;
i:integer;
slist:TStringList;
DuringTableDef,DuringIndexDef:boolean;
null:boolean;
FName,KName,TName,DName,EMask,DExpr:string;
FSize,DSize:integer;
REQ,RO,INV,CASEIN,{$IFNDEF LEVEL3}NONMT,{$ENDIF}DESC,UNIQ:boolean;
FT:TFieldType;
FK:TFieldKind;
FFields:string;
ioptions:TIndexOptions;
AIndexDef:TIndexDef;
AField:TField;
begin
if (StreamSize = 0) then exit;
ld:=sfLoadDef in sfDef;
ldidx:=sfLoadIndexDef in sfIndexDef;
// Read all definition lines in CSV format.
slist:=TStringList.Create;
DuringTableDef:=false;
DuringIndexDef:=false;
try
while true do
begin
GetLine;
if Line='' then break;
// Read magic words if any.
Word:=GetWord(null);
{$IFNDEF CSV_FILE_1XX_COMPATIBILITY}
if Word=kbmFileVersionMagic then
begin
Word:=GetWord(null);
// FileVersion:=StrToInt(Word);
continue;
end
else
{$ENDIF}
if Word=kbmTableDefMagicStart then
begin
DuringTableDef:=true;
if ld then
begin
ADataSet.Close;
ADataSet.FieldDefs.clear;
ADataSet.DeleteTable;
end;
continue;
end
// End of table definition?
else if Word=kbmTableDefMagicEnd then
begin
DuringTableDef:=false;
ADataSet.Open;
continue;
end
// Start of index definitions?
else if Word=kbmIndexDefMagicStart then
begin
if ld and ldidx then
begin
ADataSet.DestroyIndexes;
ADataSet.IndexDefs.Clear;
end;
DuringIndexDef:=true;
continue;
end
// End of index definitions?
else if Word=kbmIndexDefMagicEnd then
begin
DuringIndexDef:=false;
if ld and ldidx then ADataSet.CreateIndexes;
continue;
end;
// If not during table definitions then its the header. Break.
if not DuringTableDef then break;
// If its an index definition.
if DuringIndexDef then
begin
if ld and ldidx then
begin
Line:=ExtractQuoteString(Line,FCSVQuote);
i:=pos('=',Line);
slist.CommaText:=copy(Line,i+1,length(Line));
FName:=copy(Line,1,i-1);
FFields:=slist.Strings[0];
DName:=slist.Strings[1];
CASEIN:=pos(',CASE',Line)<>0;
{$IFNDEF LEVEL3}
NONMT:=pos(',NONMT',Line)<>0;
{$ENDIF}
DESC:=pos(',DESC',Line)<>0;
UNIQ:=pos(',UNIQ',Line)<>0;
// Add field definition.
ioptions:=[];
if CASEIN then ioptions:=ioptions+[ixCaseInSensitive];
if DESC then ioptions:=ioptions+[ixDescending];
if UNIQ then ioptions:=ioptions+[ixUnique];
{$IFNDEF LEVEL3}
if NONMT then ioptions:=ioptions+[ixNonMaintained];
AIndexDef := ADataSet.IndexDefs.AddIndexDef;
AIndexDef.Name:=FName;
AIndexDef.Fields:=FFields;
AIndexDef.Options:=ioptions;
AIndexDef.DisplayName:=DName;
{$ELSE}
IndexDefs.Add(FName,FFields,ioptions);
{$ENDIF}
end;
continue;
end;
// Otherwise its a field definition. Break the line apart.
if ld then
begin
Line:=ExtractQuoteString(Line,FCSVQuote);
i:=pos('=',Line);
slist.CommaText:=copy(Line,i+1,length(Line));
FName:=copy(Line,1,i-1);
TName:=slist.Strings[0];
FSize:=strtoint(slist.Strings[1]);
DName:=slist.Strings[2];
EMask:=slist.Strings[3];
DSize:=strtoint(slist.Strings[4]);
REQ:=pos(',REQ',Line)<>0;
RO:=pos(',RO',Line)<>0;
INV:=pos(',INV',Line)<>0;
i:=slist.Count;
DExpr:='';
if i>6 then
begin
DExpr:=slist.Strings[i-1];
dec(i);
end;
if i>5 then
KName:=slist.Strings[i-1]
else
KName:=FieldKindNames[0]; // fkData.
// Find fieldtype from fieldtypename.
for i:=0 to ord(High(FieldTypeNames)) do
if FieldTypeNames[TFieldType(i)]=TName then break;
FT:=TFieldType(i);
if not (FT in kbmSupportedFieldTypes) then
raise EMemTableError.Create(Format(kbmUnknownFieldErr1+kbmUnknownFieldErr2,[TName,Word]));
// Check if autoinc field in stream, use data from stream.
if FT=ftAutoInc then
SetIgnoreAutoIncPopulation(ADataset,true);
// If fieldkind specified, find fieldkind.
FK:=fkData;
for i:=0 to ord(High(FieldKindNames)) do
if FieldKindNames[i]=KName then
begin
FK:=TFieldKind(i);
break;
end;
// Add field definition.
ADataSet.FieldDefs.Add(FName,FT,FSize,REQ);
// Setup other properties.
i:=ADataSet.FieldDefs.IndexOf(FName);
AField:=ADataSet.FieldDefs.Items[i].CreateField(ADataset);
AField.FieldKind:=FK;
AField.DisplayLabel:=DName;
AField.EditMask:=EMask;
AField.ReadOnly:=RO;
AField.DisplayWidth:=DSize;
{$IFDEF LEVEL4}
AField.DefaultExpression:=DExpr;
{$ENDIF}
AField.Visible:=not INV;
end;
end;
finally
slist.free;
end;
FDefLoaded:=true;
end;
procedure TkbmCustomCSVStreamFormat.LoadData(ADataset:TkbmCustomMemTable);
var
i,j:integer;
nf:integer;
null:boolean;
s:string;
Accept:boolean;
LoadLine:boolean;
begin
if (StreamSize = 0) then exit;
if not (sfLoadData in sfData) then exit;
// Check if data line already loaded.
LoadLine:=not (sfLoadNoHeader in sfNoHeader);
{$IFDEF DOTNET}
if assigned (backPtr) then Marshal.FreeHGlobal(BackPtr);
lPtr:=marshal.StringToHGlobalANSI(Line); // Make sure word pointer is at start of line.
BackPtr:=lPtr;
try
{$ELSE}
lptr:=PChar(Line); // Make sure word pointer is at start of line.
{$ENDIF}
ADataSet.ResetAutoInc;
// Read all lines in CSV format.
ADataSet.LoadCount:=0;
ADataSet.LoadedCompletely:=true;
while true do
begin
if (ADataSet.LoadLimit>0) and (ADataSet.LoadCount>=ADataSet.LoadLimit) then
begin
ADataSet.LoadedCompletely:=false;
break;
end;
if LoadLine then GetLine;
LoadLine:=true;
if Line='' then break;
ADataSet.append;
i:=0;
{$IFDEF LEVEL4}
nf:=length(LoadFields);
{$ELSE}
nf:=LoadFieldsCount;
{$ENDIF}
{$IFDEF DOTNET}
while (integer(lptr)<integer(elptr)) and (i<nf) do
{$ELSE}
while (lptr<elptr) and (i<nf) do
{$ENDIF}
begin
j:=LoadFields[i];
s:=GetWord(null);
if j>=0 then
begin
if not (sfLoadFieldKind in sfFieldKind) then
begin
if ADataSet.Fields[j].FieldKind<>fkData then
begin
inc(i);
continue;
end;
end;
if assigned(FOnFormatLoadField) then
FOnFormatLoadField(self,ADataSet.Fields[j],null,s);
if null then
ADataSet.Fields[j].Clear
else if ADataSet.Fields[j].DataType in kbmStringTypes then
begin
{$IFDEF DOTNET}
s:=CodedStringToString(s);
if ADataSet.Fields[j].datasize>length(s) then
setlength(s,ADataSet.Fields[j].datasize+1);
ADataSet.Fields[j].AsString:=s;
{$ELSE}
ADataSet.Fields[j].AsString:=CodedStringToString(s);
{$ENDIF}
end
else if ADataSet.Fields[j].DataType in kbmBinaryTypes then
ADataSet.Fields[j].AsString:=Base64ToString(s)
{$IFDEF LEVEL6}
else if ADataSet.Fields[j].DataType=ftWideString then
{$IFDEF DOTNET}
ADataSet.Fields[j].Value:=s
{$ELSE}
ADataSet.Fields[j].Value:=UTF8Decode(s)
{$ENDIF}
{$ENDIF}
else if ADataSet.Fields[j].DataType = ftBoolean then
begin
if s=FCSVTrueString then
TBooleanField(ADataSet.Fields[j]).Value:=true
else
TBooleanField(ADataSet.Fields[j]).Value:=false;
end
else
ADataSet.Fields[j].AsString:=s;
if Assigned(ADataSet.OnLoadField) then ADataSet.OnLoadField(ADataSet,j,ADataSet.Fields[j]);
end;
inc(i);
end;
Accept:=true;
if Assigned(ADataSet.OnLoadRecord) then ADataSet.OnLoadRecord(ADataset,Accept);
if Accept then
begin
ADataSet.Post;
ADataSet.LoadCount:=ADataSet.LoadCount+1;
end
else
ADataSet.Cancel;
end;
{$IFDEF DOTNET}
finally
Marshal.FreeHGlobal(BackPtr);
BackPtr:=nil;
end;
{$ENDIF}
end;
// -----------------------------------------------------------------------------------
// Registration for Delphi 3 / C++ Builder 3
// -----------------------------------------------------------------------------------
{$ifdef LEVEL3}
procedure Register;
begin
RegisterComponents('kbmMemTable', [TkbmCSVStreamFormat]);
end;
{$endif}
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -