现在的位置: 首页 > 综合 > 正文

转贴一篇 自定义数据库 希望对你有帮助

2011年08月02日 ⁄ 综合 ⁄ 共 10540字 ⁄ 字号 评论关闭

//---------------------------------------------------------------------------
//(R)CopyRight KivenSoft International ,inc 1999
//单元名称:数据库单元
//程序名称:电子书库
//作    者:李会文
//开始时间:1998.07.28
//最后修改:1999.07.22
//备注:此单元定义了SRM文件的读写接口
//---------------------------------------------------------------------------
unit SrmUnit;

interface

uses
  Windows,SysUtils,Classes, SrmConst;

type
PCharArray=^TCharArray;
TCharArray=array[0..0] of char;
PDwordArray=^TDwordArray;
TDwordArray=array[0..0] of DWORD;
PIntArray=^TIntArray;
TIntArray=array[0..0] of integer;

PTreeData=^TTreeData;
TTreeData=record        //索引信息
  Pos: longint;
  DataType: longint;
end;
PTdArray=^TTdArray;
TTdArray=array[0..0] of TTreeData;

PFileHead=^TFileHead;
TFileHead=record
  OpenFlag      :Longint;                      //数据库打开标志
  LastViewPos   :longint;                   //关闭时的位置
  IndexPos      :longint;                   //索引位置
  EditDate      :TDateTime;                 //最后修改日期
  Key           :DWORD;                     //密钥
  Password      :array[0..11] of char;      //口令
  Author        :array[0..15] of char;      //作者
  BuildDate     :TDateTime;                 //建库日期
  DataType      :longint;                   //数据库格式
  DataFlag      :array[0..7] of char;       //数据库标志
  Version       :longint;                   //数据库版本
  BookMerg      :array[0..9] of longint;    //10个书签
  Keep          :longint;                   //保留字段
end;

//DataType 0:Index    1:Normal Dir     2:Notmal TXT    3:Normal HTML
PIndexHead=^TIndexHead;
TIndexHead=record
  DataType      :longint;                   //段类型
  Key           :DWORD;                     //密钥
  Count         :longint;                   //标题数量
  Size          :longint;                   //标题长度
  Keep          :longint;                   //保留字段
end;

PDataHead=^TDataHead;
TDataHead=record
  DataType      :longint;                   //段类型
  Author        :array[0..15] of char;      //作者
  PubDate       :TDateTime;                 //收录日期
  Key           :DWORD;                     //密钥
  Num           :longint;                   //附件数量
  SearchKey     :array[0..51] of char;      //关键词
  Password      :array[0..11] of char;      //口令
  Keep          :longint;                   //保留字段
end;

//------------------------------------------------------------------------
TSrmObject=class
  private
    FChangeFlag         :boolean;   //在文件后有增加新信息的变量
    FDbChanged          :boolean;   //数据库属性有变动
    FIndexChanged       :boolean;   //索引有变动
    FItemHeadChanged    :boolean;   //标题头有变动
    FItemDataChanged    :boolean;   //标题内容有变动
    FFileHead           :TFileHead;
    FIndexHead          :TIndexHead;
    FDataHead           :TDataHead;
    FFileHandle         :integer;       //文件句柄
    FFileName           :string;
    FActivePos          :longint;       //当前读出内容的位置

    procedure Encypher(Cypher:DWORD;var Buf;Count:integer);
    procedure Decypher(Cypher:DWORD;var Buf;Count:integer);
    procedure CreateSrmFile;            //建立一个空数据库
    procedure SetDbChanged(Value:boolean);
    procedure SetIndexChanged(Value:boolean);
    procedure SetItemHeadChanged(Value:boolean);
    procedure SetItemDataChanged(Value:boolean);
  public
    property FileName:string read FFileName;
    property FileHead:TFileHead read FFileHead write FFileHead;
    property IndexHead:TIndexHead read FIndexHead write FIndexHead;
    property DataHead:TDataHead read FDataHead write FDataHead;
    property ActivePos:longint read FActivePos write FActivePos;
    property DbChanged:boolean read FDbChanged write SetDbChanged;
    property IndexChanged:boolean read FIndexChanged write SetIndexChanged;
    property ItemHeadChanged:boolean read FItemHeadChanged write SetItemHeadChanged;
    property ItemDataChanged:boolean read FItemDataChanged write SetItemDataChanged;

    constructor Create(Fn:string;Mode:Word);
    destructor Destroy;override;
    procedure Free;
    procedure SaveSrmFile;          //不关闭文件情况下保存文件
    procedure LoadIndex(Msh,Msd:TMemoryStream); //读索引
    procedure SaveIndex(Msh,Msd:TMemoryStream);//写索引
    class function IsSrmFile(var Fn:string):boolean;//判断是否是SRM格式数据库文件
    procedure ReadItemHead(Ps:longint);  //读数据段头
    procedure ReadItemData(DataStream:TMemoryStream);  //读数据段内容
    procedure EditItemHead(Ps:longint);    //修改数据头
    function AddItemHead:longint;          //写数据段头
    procedure AddItemData(DataStream:TMemoryStream); //写数据段内容
    function GetItemPassword(Ps:longint):string; //得某标题口令
 end;
//------------------------------------------------------------------------

implementation

//------------------------------------------------------------------------
procedure TSrmObject.Encypher(Cypher:DWORD;var Buf;Count:integer);
var
  i:integer;
begin
  Cypher:=not Cypher;
  Dec(Count);
  for i:=0 to Count do
    TDwordArray(Buf)[i]:=TDwordArray(Buf)[i] xor Cypher;
end;

procedure TSrmObject.Decypher(Cypher:DWORD;var Buf;Count:integer);
var
  i:integer;
begin
  Cypher:=not Cypher;
  Dec(Count);
  for i:=0 to Count do
    TDwordArray(Buf)[i]:=TDwordArray(Buf)[i] xor Cypher;
end;
//------------------------------------------------------------------------

procedure TSrmObject.CreateSrmFile;    //建立一个空数据库
var
  i:integer;
begin
    FFileHandle:=FileCreate(FFileName);
    if FFileHandle=-1 then raise Exception.Create(csCanNotCreate);
    //添充缺省信息头
    with FFileHead do
    begin
      OpenFlag:=0;
      LastViewPos:=0;
      IndexPos:=sizeof(TFileHead);
      EditDate:=Now;
      Key:=GetTickCount;
      Password[0]:=#0;
      Author[0]:=#0;
      BuildDate:=EditDate;
      DataType:=0;
      Version:=3;
      Keep:=0;
      DataFlag[0]:='K';
      DataFlag[1]:='i';
      DataFlag[2]:='v';
      DataFlag[3]:='e';
      DataFlag[4]:='n';
      for i:=0 to 9 do BookMerg[i]:=-1;
    end;
    //添充缺省索引
    with FIndexHead do
    begin
      DataType:=0;
      Key:=GetTickCount;
      Count:=0;
      Size:=0;
      Keep:=0;
    end;
    //加密写入文件后解密
    with FFileHead do
    begin
      Encypher(Key,Author,4);
      Encypher(Key,Password,3);
      FileWrite(FFileHandle,FFileHead,sizeof(TFileHead));
      FileWrite(FFileHandle,FIndexHead,sizeof(TIndexHead));
      Decypher(Key,Author,4);
      Decypher(Key,Password,3);
    end;
end;

constructor TSrmObject.Create(Fn:string;Mode:Word);
begin
  FFileName:=Fn;
  FChangeFlag:=false;
  FDbChanged:=false;
  FIndexChanged:=false;
  FItemHeadChanged:=false;
  FItemDataChanged:=false;
  FDataHead.Keep:=0;
  //打开文件时读文件头,否则建新文件
  if Mode=fmOpenReadWrite then
  begin
    FFileHandle:=FileOpen(FFileName,fmOpenReadWrite);
    FileRead(FFileHandle,FFileHead,sizeof(TFileHead));
    with FFileHead do
    begin
      Decypher(Key,Password,3);
      Decypher(Key,Author,4);
    end;
  end
  else if Mode=fmCreate then
  begin
    CreateSrmFile;
  end;
end;

destructor TSrmObject.Destroy;
begin
  if FFileHandle<>-1 then
  begin
    FileClose(FFileHandle);  //关闭文件
    FFileHandle:=-1;
  end;
  inherited;
end;

procedure TSrmObject.Free;
begin
  if Assigned(self) then Destroy;
end;

procedure TSrmObject.SaveSrmFile;
begin
  //写入更新后的文件头
  with FFileHead do
  begin
    FileSeek(FFileHandle,0,0);
    EditDate:=Now;
    Key:=GetTickCount;
    Encypher(Key,Password,3);
    Encypher(Key,Author,4);
    FileWrite(FFileHandle,FFileHead,sizeof(TFileHead));
    Decypher(Key,Password,3);
    Decypher(Key,Author,4);
  end;
end;

class function TSrmObject.IsSrmFile(var Fn:string):boolean;
var
  Fh: TFileHead;
  Fs: TFileStream;
begin
  Result:=false;
  Fs:=TFileStream.Create(Fn,fmOpenRead);
  //根据文件长度判断
  with Fs do
  begin
    if (Size<(sizeof(TFileHead)+sizeof(TIndexHead))) then
    begin
      Free;
      Result:=false;
      Exit;
    end;
    Read(Fh,sizeof(TFileHead));
    Free;
  end;
  //根据文件标志判断
  with Fh do
  begin
    if ( (DataFlag[0]='K') and (DataFlag[1]='i') and
        (DataFlag[2]='v') and (DataFlag[3]='e') and
        (DataFlag[4]='n') ) then
      Result:=true;
  end;
end;

procedure TSrmObject.LoadIndex(Msh,Msd:TMemoryStream);
begin
  //读出索引头
  FileSeek(FFileHandle,FFileHead.IndexPos,0);
  FileRead(FFileHandle,FIndexHead,sizeof(TIndexHead));
  //处理索引长度为0的状况,否则读出具体索引
  if (FIndexHead.Size=0) then
  begin
    Msh.SetSize(0);
    Msd.SetSize(0);
  end
  else
  begin
    Msh.SetSize(FIndexHead.Size);
    Msd.SetSize(FIndexHead.Count*sizeof(longint)*2);
    FileRead(FFileHandle,Msh.Memory^,Msh.Size);
    FileRead(FFileHandle,Msd.Memory^,Msd.Size);
    Decypher(FIndexHead.Key,Msh.Memory^,Msh.Size div 4);
  end;
end;

procedure TSrmObject.SaveIndex(Msh,Msd:TMemoryStream);
begin
  if FChangeFlag then  //增加过新内容时
    FFileHead.IndexPos:=FileSeek(FFileHandle,0,2)
  else                 //无新增内容
    FileSeek(FFileHandle,FFileHead.IndexPos,0);
  //设置数据头
  with FIndexHead do
  begin
    Key:=GetTickCount;
    Size:=Msh.Size;
    Count:=Msd.Size div (sizeof(longint)*2);
  end;
  //加密标题内容
  Encypher(FIndexHead.Key,Msh.Memory^,Msh.Size div 4);
  //写入索引
  FileWrite(FFileHandle,FIndexHead,sizeof(TIndexHead));
  FileWrite(FFileHandle,Msh.Memory^,Msh.Size);
  FileWrite(FFileHandle,Msd.Memory^,Msd.Size);
end;

procedure TSrmObject.ReadItemHead(Ps:longint);
begin
  FActivePos:=Ps;  //保存当前数据位置
  //读出并解密
  with FDataHead do
  begin
    FileSeek(FFileHandle,Ps,0);
    FileRead(FFileHandle,FDataHead,sizeof(TDataHead));
    Decypher(Key,SearchKey,13);
    Decypher(Key,Author,4);
    Decypher(Key,Password,3);
  end;
end;

procedure TSrmObject.ReadItemData(DataStream:TMemoryStream);
var
  size:longint;
begin
  //读出具体内容
  FileRead(FFileHandle,size,sizeof(longint));
  DataStream.SetSize(size);
  FileRead(FFileHandle,DataStream.Memory^,size);
  Decypher(FDataHead.Key,DataStream.Memory^,size div 4);
end;

procedure TSrmObject.EditItemHead(Ps:longint);
begin
  //修改数据头
  FileSeek(FFileHandle,Ps,0);
  with FDataHead do
  begin
    Encypher(Key,SearchKey,13);
    Encypher(Key,Author,4);
    Encypher(Key,Password,3);
    FileWrite(FFileHandle,FDataHead,sizeof(TDataHead));
    Decypher(Key,SearchKey,13);
    Decypher(Key,Author,4);
    Decypher(Key,Password,3);
  end;
end;

function TSrmObject.AddItemHead:longint;
begin
  //新内容增加时移到文件尾添加
  FChangeFlag:=true;
  with FDataHead do
  begin
    Result:=FileSeek(FFileHandle,0,2);
    Key:=GetTickCount;
    PubDate:=Now;
    Encypher(Key,SearchKey,13);
    Encypher(Key,Author,4);
    Encypher(Key,Password,3);
    FileWrite(FFileHandle,FDataHead,sizeof(TDataHead));
    Decypher(Key,SearchKey,13);
    Decypher(Key,Author,4);
    Decypher(Key,Password,3);
  end;
end;

procedure TSrmObject.AddItemData(DataStream:TMemoryStream);
var
  size:longint;
begin
  size:=DataStream.Size;
  FileWrite(FFileHandle,size,sizeof(longint));
  Encypher(FDataHead.Key,DataStream.Memory^,size div 4);
  FileWrite(FFileHandle,DataStream.Memory^,size);
end;

function TSrmObject.GetItemPassword(Ps:longint):string; //得某标题口令
var
  Dh:TDataHead;
begin
  //读出并解密
  with Dh do
  begin
    FileSeek(FFileHandle,Ps,0);
    FileRead(FFileHandle,Dh,sizeof(TDataHead));
    Decypher(Key,Password,3);
  end;
  result:=string(Dh.Password);
end;

procedure TSrmObject.SetDbChanged(Value:boolean);
begin
  FDbChanged:=Value;
end;

procedure TSrmObject.SetIndexChanged(Value:boolean);
begin
  FIndexChanged:=Value;
  if Value then FDbChanged:=Value;
end;

procedure TSrmObject.SetItemHeadChanged(Value:boolean);
begin
  FItemHeadChanged:=Value;
  if Value then
  begin
    FIndexChanged:=Value;
    FDbChanged:=Value;
  end;
end;

procedure TSrmObject.SetItemDataChanged(Value:boolean);
begin
  FItemDataChanged:=Value;
  if Value then
  begin
    FIndexChanged:=Value;
    FDbChanged:=Value;
  end;
end;

 

end.

抱歉!评论已关闭.