📄 dbf_dbffile.pas
字号:
begin
FFileCodePage := 1255;
end else begin
FFileCodePage := GetIntFromStrLength(LangStr+2, 3, 0);
if (Ord(LangStr[5]) >= Ord('0')) and (Ord(LangStr[5]) <= Ord('9')) then
FFileCodePage := FFileCodePage * 10 + Ord(LangStr[5]) - Ord('0');
end;
end else
if StrLComp(LangStr, 'FOX', 3) = 0 then
begin
if StrLComp(LangStr+5, 'WIN', 3) = 0 then
FFileCodePage := 1252
else
FFileCodePage := GetIntFromStrLength(LangStr+5, 3, 0)
end else begin
FFileCodePage := 0;
end;
FFileLangId := GetLangId_From_LangName(LanguageStr);
end else begin
// FDbfVersion <= xBaseV
FFileLangId := PDbfHdr(Header)^.Language;
FFileCodePage := LangId_To_CodePage[FFileLangId];
end;
// determine used codepage, if no codepage, then use default codepage
FUseCodePage := FFileCodePage;
if FUseCodePage = 0 then
FUseCodePage := DbfGlobals.DefaultOpenCodePage;
// get list of fields
ConstructFieldDefs;
// open blob file if present
lMemoFileName := ChangeFileExt(FileName, GetMemoExt);
if HasBlob then
begin
// open blob file
if not FileExists(lMemoFileName) then
MemoFileClass := TNullMemoFile
else if FDbfVersion = xFoxPro then
MemoFileClass := TFoxProMemoFile
else
MemoFileClass := TDbaseMemoFile;
FMemoFile := MemoFileClass.Create(Self);
FMemoFile.FileName := lMemoFileName;
FMemoFile.Mode := Mode;
FMemoFile.AutoCreate := false;
FMemoFile.MemoRecordSize := 0;
FMemoFile.DbfVersion := FDbfVersion;
FMemoFile.Open;
// set header blob flag corresponding to field list
if FDbfVersion <> xFoxPro then
begin
PDbfHdr(Header)^.VerDBF := PDbfHdr(Header)^.VerDBF or $80;
lModified := true;
end;
end else
if FDbfVersion <> xFoxPro then
begin
PDbfHdr(Header)^.VerDBF := PDbfHdr(Header)^.VerDBF and $7F;
lModified := true;
end;
// check if mdx flagged
if (FDbfVersion <> xFoxPro) and (PDbfHdr(Header)^.MDXFlag <> 0) then
begin
// open mdx file if present
lMdxFileName := ChangeFileExt(FileName, '.mdx');
if FileExists(lMdxFileName) then
begin
// open file
FMdxFile := TIndexFile.Create(Self);
FMdxFile.FileName := lMdxFileName;
FMdxFile.Mode := Mode;
FMdxFile.AutoCreate := false;
FMdxFile.OnLocaleError := FOnLocaleError;
FMdxFile.CodePage := UseCodePage;
FMdxFile.Open;
// is index ready for use?
if not FMdxFile.ForceClose then
begin
FIndexFiles.Add(FMdxFile);
// get index tag names known
FMdxFile.GetIndexNames(FIndexNames);
end else begin
// asked to close! close file
FreeAndNil(FMdxFile);
end;
end else begin
// ask user
deleteLink := true;
if Assigned(FOnIndexMissing) then
FOnIndexMissing(deleteLink);
// correct flag
if deleteLink then
begin
PDbfHdr(Header)^.MDXFlag := 0;
lModified := true;
end else
FForceClose := true;
end;
end;
end;
// record changes
if lModified then
WriteHeader;
// open indexes
for I := 0 to FIndexFiles.Count - 1 do
TIndexFile(FIndexFiles.Items[I]).Open;
end;
end;
procedure TDbfFile.Close;
var
MdxIndex, I: Integer;
begin
if Active then
begin
// close index files first
MdxIndex := -1;
for I := 0 to FIndexFiles.Count - 1 do
begin
TIndexFile(FIndexFiles.Items[I]).Close;
if TIndexFile(FIndexFiles.Items[I]) = FMdxFile then
MdxIndex := I;
end;
// free memo file if any
FreeAndNil(FMemoFile);
// now we can close physical dbf file
CloseFile;
// free FMdxFile, remove it from the FIndexFiles and Names lists
if MdxIndex >= 0 then
FIndexFiles.Delete(MdxIndex);
I := 0;
while I < FIndexNames.Count do
begin
if FIndexNames.Objects[I] = FMdxFile then
begin
FIndexNames.Delete(I);
end else begin
Inc(I);
end;
end;
FreeAndNil(FMdxFile);
FreeMemAndNil(Pointer(FPrevBuffer));
FreeMemAndNil(Pointer(FDefaultBuffer));
// reset variables
FFileLangId := 0;
end;
end;
procedure TDbfFile.FinishCreate(AFieldDefs: TDbfFieldDefs; MemoSize: Integer);
var
lFieldDescIII: rFieldDescIII;
lFieldDescVII: rFieldDescVII;
lFieldDescPtr: Pointer;
lFieldDef: TDbfFieldDef;
lMemoFileName: string;
I, lFieldOffset, lSize, lPrec: Integer;
lHasBlob: Boolean;
lLocaleID: LCID;
begin
try
// first reset file
RecordCount := 0;
lHasBlob := false;
// determine codepage & locale
if FFileLangId = 0 then
FFileLangId := DbfGlobals.DefaultCreateLangId;
FFileCodePage := LangId_To_CodePage[FFileLangId];
lLocaleID := LangId_To_Locale[FFileLangId];
FUseCodePage := FFileCodePage;
// prepare header size
if FDbfVersion = xBaseVII then
begin
// version xBaseVII without memo
HeaderSize := SizeOf(rDbfHdr) + SizeOf(rAfterHdrVII);
RecordSize := SizeOf(rFieldDescVII);
FillChar(Header^, HeaderSize, #0);
PDbfHdr(Header)^.VerDBF := $04;
// write language string
StrPLCopy(
@PAfterHdrVII(PChar(Header)+SizeOf(rDbfHdr))^.LanguageDriverName[32],
ConstructLangName(FFileCodePage, lLocaleID, false),
63-32);
lFieldDescPtr := @lFieldDescVII;
end else begin
// version xBaseIII/IV/V without memo
HeaderSize := SizeOf(rDbfHdr) + SizeOf(rAfterHdrIII);
RecordSize := SizeOf(rFieldDescIII);
FillChar(Header^, HeaderSize, #0);
if FDbfVersion = xFoxPro then
begin
PDbfHdr(Header)^.VerDBF := $02
end else
PDbfHdr(Header)^.VerDBF := $03;
// standard language WE, dBase III no language support
if FDbfVersion = xBaseIII then
PDbfHdr(Header)^.Language := 0
else
PDbfHdr(Header)^.Language := FFileLangId;
// init field ptr
lFieldDescPtr := @lFieldDescIII;
end;
// begin writing fields
FFieldDefs.Clear;
// deleted mark 1 byte
lFieldOffset := 1;
for I := 1 to AFieldDefs.Count do
begin
lFieldDef := AFieldDefs.Items[I-1];
// check if datetime conversion
if FCopyDateTimeAsString then
if lFieldDef.FieldType = ftDateTime then
begin
// convert to string
lFieldDef.FieldType := ftString;
lFieldDef.Size := 22;
end;
// update source
lFieldDef.FieldName := AnsiUpperCase(lFieldDef.FieldName);
lFieldDef.Offset := lFieldOffset;
lHasBlob := lHasBlob or lFieldDef.IsBlob;
// apply field transformation tricks
lSize := lFieldDef.Size;
lPrec := lFieldDef.Precision;
if (lFieldDef.NativeFieldType = 'C')
{$ifndef USE_LONG_CHAR_FIELDS}
and (FDbfVersion = xFoxPro)
{$endif}
then
begin
lPrec := lSize shr 8;
lSize := lSize and $FF;
end;
// update temp field props
if FDbfVersion = xBaseVII then
begin
FillChar(lFieldDescVII, SizeOf(lFieldDescVII), #0);
StrPLCopy(lFieldDescVII.FieldName, lFieldDef.FieldName, SizeOf(lFieldDescVII.FieldName)-1);
lFieldDescVII.FieldType := lFieldDef.NativeFieldType;
lFieldDescVII.FieldSize := lSize;
lFieldDescVII.FieldPrecision := lPrec;
lFieldDescVII.NextAutoInc := SwapIntLE(lFieldDef.AutoInc);
//lFieldDescVII.MDXFlag := ???
end else begin
FillChar(lFieldDescIII, SizeOf(lFieldDescIII), #0);
StrPLCopy(lFieldDescIII.FieldName, lFieldDef.FieldName, SizeOf(lFieldDescIII.FieldName)-1);
lFieldDescIII.FieldType := lFieldDef.NativeFieldType;
lFieldDescIII.FieldSize := lSize;
lFieldDescIII.FieldPrecision := lPrec;
if FDbfVersion = xFoxPro then
lFieldDescIII.FieldOffset := SwapIntLE(lFieldOffset);
if (PDbfHdr(Header)^.VerDBF = $02) and (lFieldDef.NativeFieldType in ['0', 'Y', 'T', 'O', '+']) then
PDbfHdr(Header)^.VerDBF := $30;
if (PDbfHdr(Header)^.VerDBF = $30) and (lFieldDef.NativeFieldType = '+') then
PDbfHdr(Header)^.VerDBF := $31;
end;
// update our field list
with FFieldDefs.AddFieldDef do
begin
Assign(lFieldDef);
Offset := lFieldOffset;
AutoInc := 0;
end;
// save field props
WriteRecord(I, lFieldDescPtr);
Inc(lFieldOffset, lFieldDef.Size);
end;
// end of header
WriteChar($0D);
// write memo bit
if lHasBlob then
begin
if FDbfVersion = xBaseIII then
PDbfHdr(Header)^.VerDBF := PDbfHdr(Header)^.VerDBF or $80
else
if FDbfVersion = xFoxPro then
begin
if PDbfHdr(Header)^.VerDBF = $02 then
PDbfHdr(Header)^.VerDBF := $F5;
end else
PDbfHdr(Header)^.VerDBF := PDbfHdr(Header)^.VerDBF or $88;
end;
// update header
PDbfHdr(Header)^.RecordSize := lFieldOffset;
PDbfHdr(Header)^.FullHdrSize := HeaderSize + RecordSize * AFieldDefs.Count + 1;
// add empty "back-link" info, whatever it is:
{ A 263-byte range that contains the backlink, which is the relative path of
an associated database (.dbc) file, information. If the first byte is 0x00,
the file is not associated with a database. Therefore, database files always
contain 0x00. }
if FDbfVersion = xFoxPro then
Inc(PDbfHdr(Header)^.FullHdrSize, 263);
// write dbf header to disk
inherited WriteHeader;
finally
RecordSize := PDbfHdr(Header)^.RecordSize;
HeaderSize := PDbfHdr(Header)^.FullHdrSize;
// write full header to disk (dbf+fields)
WriteHeader;
end;
if HasBlob and (FMemoFile=nil) then
begin
lMemoFileName := ChangeFileExt(FileName, GetMemoExt);
if FDbfVersion = xFoxPro then
FMemoFile := TFoxProMemoFile.Create(Self)
else
FMemoFile := TDbaseMemoFile.Create(Self);
FMemoFile.FileName := lMemoFileName;
FMemoFile.Mode := Mode;
FMemoFile.AutoCreate := AutoCreate;
FMemoFile.MemoRecordSize := MemoSize;
FMemoFile.DbfVersion := FDbfVersion;
FMemoFile.Open;
end;
end;
function TDbfFile.HasBlob: Boolean;
var
I: Integer;
begin
Result := false;
for I := 0 to FFieldDefs.Count-1 do
if FFieldDefs.Items[I].IsBlob then
Result := true;
end;
function TDbfFile.GetMemoExt: string;
begin
if FDbfVersion = xFoxPro then
Result := '.fpt'
else
Result := '.dbt';
end;
procedure TDbfFile.Zap;
begin
// make recordcount zero
RecordCount := 0;
// update recordcount
PDbfHdr(Header)^.RecordCount := RecordCount;
// update disk header
WriteHeader;
// update indexes
RegenerateIndexes;
end;
procedure TDbfFile.WriteHeader;
var
SystemTime: TSystemTime;
lDataHdr: PDbfHdr;
EofTerminator: Byte;
begin
if (HeaderSize=0) then
exit;
//FillHeader(0);
lDataHdr := PDbfHdr(Header);
GetLocalTime(SystemTime);
lDataHdr^.Year := SystemTime.wYear - 1900;
lDataHdr^.Month := SystemTime.wMonth;
lDataHdr^.Day := SystemTime.wDay;
// lDataHdr.RecordCount := RecordCount;
inherited WriteHeader;
EofTerminator := $1A;
WriteBlock(@EofTerminator, 1, CalcPageOffset(RecordCount+1));
end;
procedure TDbfFile.ConstructFieldDefs;
var
{lColumnCount,}lHeaderSize,lFieldSize: Integer;
lPropHdrOffset, lFieldOffset: Integer;
lFieldDescIII: rFieldDescIII;
lFieldDescVII: rFieldDescVII;
lFieldPropsHdr: rFieldPropsHdr;
lStdProp: rStdPropEntry;
TempFieldDef: TDbfFieldDef;
lSize,lPrec,I, lColumnCount: Integer;
lAutoInc: Cardinal;
dataPtr: PChar;
lNativeFieldType: Char;
lFieldName: string;
lCanHoldNull: boolean;
lCurrentNullPosition: integer;
begin
FFieldDefs.Clear;
if DbfVersion >= xBaseVII then
begin
lHeaderSize := SizeOf(rAfterHdrVII) + SizeOf(rDbfHdr);
lFieldSize := SizeOf(rFieldDescVII);
end else begin
lHeaderSize := SizeOf(rAfterHdrIII) + SizeOf(rDbfHdr);
lFieldSize := SizeOf(rFieldDescIII);
end;
HeaderSize := lHeaderSize;
RecordSize := lFieldSize;
FLockField := nil;
FNullField := nil;
FAutoIncPresent := false;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -