CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  Delphi >  数据库相关

如何在DELPHI程序中作数据库的pack操作?

楼主to(天佑)2002-03-24 12:00:58 在 Delphi / 数据库相关 提问

paradox   的数据库记录被删除后,如何在程序中对数据库进行整理(pack)?  
  问题点数:50、回复次数:1Top

1 楼forgot(忘记forgot2000)回复于 2002-03-24 12:13:14 得分 50

为Delphi提供Pack和Undelete功能    
   
  本文针对Delphi3和Delphi4,对于C++Builder同样也适用,在数据库引擎BDE4.0、4.5、5.0中经过测试。  
   
  Delphi目前已经是国内常见的数据库编程工具,它在各方面表现不错,在支持大型多层数据库结构的同时也完全支持本地数据库的支持。对于本地数据库中Delphi对FoxPro2.5b的支持也不错,我曾经对VB、FoxPro2.5b、Delphi的数据库操作速度进行比较,发现除了启动速度较慢外,其它各项Delphi均排在首位。而且Delphi几乎支持所有原先FoxPro所拥有的功能,对于有一定编程经验的人来说,Delphi成了编写数据库软件的一把利器,因而Delphi迅速流行起来,我几年前甚至利用Delphi   1.0和汇编配合制作了工业控制系统的实时前后台软件。  
   
  但是在我长期使用Delphi编程的过程中发现它也有不如人意的地方,特别是在本地数据库FoxPro方面,它居然不支持十分有用的Pack和Undelete功能。对于数据库来说,因为是一个顺序存储文件,在删除部分记录是一般采用了软删除技术,也就是说将要删除的记录标记已删除的标记,但并不立即从物理上删除这些记录。这样做可以避免仅仅删除一条记录就要将整个数据库重新写入存储器,提高了读写的效率。但是如果数据库长期不对已经被标记为删除的记录进行整理和真实删除,数据库就会越来越大,其中无用的数据所占的比率越来越大,使得数据库的读写效率迅速下降,而且造成查询速度的减慢。在编写FoxPro数据库时有个规律,如果数据进出数据库频繁,也就是说不断删除旧的数据,加入新的数据的情况下每次在关闭数据库的时候或打开数据库的时候先做一次Pack,对数据库进行整理,将软删除的记录真正从数据库中删除。但是在Delphi的各个版本中数据库控件均未提供Pack的功能,这使得用Delphi编写的数据库软件如果使用本地数据库的形式,数据库的大小增长很快,即使删除了大量记录,数据库的大小没有任何改变。以前我的做法是在使用这类数据库软件一段时间后利用FoxPro打开数据库进行Pack,但是这样做要求客户端拥有FoxPro,而且经常这么做也很繁。于是我开始查找有关资料,为什么Delphi无法使用pack功能?  
   
  经过再三查找,我找到一些资料,说明如何对数据库进行pack了,在将其改编后在Delphi中使用通过。下面是其中的核心程序。  
   
  BDE   API   Call:  
   
  DBIResult   DBIFN   DbiPackTable   (hDb,   hCursor,   pszTableName,   [  
   
  pszDriverType],   bRegenIdxs);  
   
  在数据库引擎的底层函数调用中,我找到了这个函数,这个函数据说可以对FoxPro的数据库进行Pack,其中hDb是数据库的句柄,可以由Table.Handle获得;hCursor是数据表(Table)关联的游标,如果为NULL则数据表依赖于pszTableName和pszDriverType这两个传输决定数据库的来源;bRegenIdxs决定是否关联外接的索引文件尤其是MDX多索引文件。  
   
  具体的操作函数如下:  
   
  procedure   PackTable(Table:   TTable);  
   
  var  
   
  Props:   CURProps;  
   
  hDb:   hDBIDb;  
   
  begin  
   
  if   not   Table.Active   then  
   
  raise   EDatabaseError.Create('Table必需已经打开');  
   
  if   not   Table.Exclusive   then  
   
  raise   EDatabaseError.Create('Table必需以独占方式打开');  
   
  Check(DbiGetCursorProps(Table.Handle,   Props));  
   
  if   (Props.szTableType   =   szDBASE)   then  
   
  Check(DbiPackTable(Table.DBHandle,   Table.Handle,   nil,   szDBASE,   True))  
   
  else  
   
  raise   EDatabaseError.Create('Table必需是dBASE或FoxPro类型');  
   
  Table.Open;  
   
  end;  
   
  特别对这段源码说明一下,这段源码部分改编自C,已经在上面提到过的环境中测试通过,需要注意的是,数据表必需以独占方式打开,简单的说,就是在设计时将数据表关闭(属性Active=False),在运行时才打开数据表(form_onCreate时Table.Open),这样才能保证数据表在独占方式下被打开。DbiGetCursorProps()是一个读取数据表的属性的底层函数调用,返回了大部分通用的数据表属性。Check()函数可以简单的处理数据库的出错提示和异常处理,如果出现函数调用错误会自动显示出错信息。  
   
  说了pack那么与之对应的Undelete也就更要解释了,同样我找到了将软删除的数据恢复的函数,不过这个函数隐藏的更深,连C代码都没有,所以以下的代码完全由我自己摸索出来,仅在上面说到的环境中测试通过。  
   
  首先介绍一下相应的底层函数调用:  
   
  DBIResult   DBIFN   DbiUndeleteRecord   (hCursor);  
   
  这个函数仅有的参数就是关联的数据表的游标,您可以在BDE.int的文件中找到它的声明,但是具体的使用说明含糊不清,到底是恢复当前被删记录还是将数据表内所有被软删除的记录全部恢复?由于缺少相应的代码分析,我参照FoxPro的经验进行了多次实验,在十几种方案的对比下得出了结论,这条函数调用仅仅恢复当前的被软删除的记录。因此必需首先将数据表的游标移动到被删除的记录上,然后调用这条函数,才会有所反应。要知道在默认的情况下,数据库控件是不会将游标移动到被删除的记录上的,所以必需首先将数据表的读写属性修改,打开软删除的属性,使得遍历数据表时可以访问到被标记为删除的记录。下面是一段实现将数据表中所有被软删除的记录恢复的源代码。其它形式的反删除可以参照这段代码。  
   
  procedure   Ttablepro.undelete;  
   
  var  
   
  CProps:   CurProps;  
   
  rslt:   DBIResult;  
   
  bm:TBookmark;  
   
  rp:pRECProps;  
   
  begin  
   
  Check(DbiGetCursorProps(self.Handle,   CProps));//取得数据表的属性  
   
  if   (StrIComp(CProps.szTableType,   szDBASE)   <>   0)   then//如果不是Dbase或Foxpro则退出  
   
  raise   EDBEngineError.Create(DBIERR_NOTSUPPORTED);  
   
  rslt:=DbiValidateProp(hDBIObj(self.Handle),   curSOFTDELETEON,   True);  
   
  //可否设置软删除?  
   
  if   (rslt   =   DBIERR_NONE)   then  
   
  Check(DbiSetProp(hDBIObj(self.Handle),   curSOFTDELETEON,   Longint(true)));  
   
  //设置为可以软删除  
   
  Check(DbiGetCursorProps(self.Handle,   CProps));  
   
  //更新数据表的属性  
   
  if   (CProps.bDeletedOn   =   False)   then  
   
  raise   EDatabaseError.Create('软删除没有设置!');  
   
  //取得当前的记录位置  
   
  bm:=self.GetBookmark;  
   
  //将游标移动到第一个记录以前!Not   Table.First!  
   
  Check(DbiSetTobegin(self.handle));  
   
  //不断移动,直到到数据表的最后记录  
   
  while   (DBIGETNEXTRECORD(self.handle,dbinolock,nil,nil)=DBIERR_NONE)   do  
   
  begin  
   
  //请关闭Delphi的异常响应,以便执行下面的语句!  
   
  try  
   
  check(DbiUndeleteRecord(self.Handle));  
   
  except  
   
  //Do   somthing   here   !  
   
  end;  
   
  end;  
   
  //取回原先记录的位置,重新定位  
   
  self.GotoBookmark(bm);  
   
  self.FreeBookmark(bm);  
   
  self.Refresh;  
   
  end;  
   
  (注:如果可以,请在刊登时删去“Self.refresh”一行,对于原理的介绍无需此行,仅在我的控件的属性中需要,以上代码来自我制作的Delphi控件TTablePro)Top

相关问题

  • delphi如何操作dbf数据库?
  • 求delphi操作数据库代码
  • delphi对数据库操作时,如何锁定操作状态
  • 数据库操作
  • 数据库操作
  • 数据库操作
  • DELPHI 对数据库的操作如何进行 ?
  • 请问如何在delphi中连接并操作oracle数据库?
  • delphi 操作oracle数据库的问题,急急急!!!
  • Delphi 中如何TQuery进行数据库表的插入操作?

关键词

  • 数据库
  • 函数
  • delphi
  • foxpro
  • 属性
  • 代码
  • 控件
  • 数据表
  • 删除
  • 记录

得分解答快速导航

  • 帖主:to
  • forgot

相关链接

  • Delphi类图书
  • Delphi类源码下载
  • Delphi控件下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo