全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1469
推到 Plurk!
推到 Facebook!

為Delphi提供Pack和Undelete功能返回

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-12-29 01:53:08 IP:61.64.xxx.xxx 未訂閱
主題:為Delphi提供Pack和Undelete功能返回 日期: 1991/3/30 作者: 本文針對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) 在這段代碼中已經有了詳細的解釋,應該可以比較容易的瞭解undelete的技巧了。當然如果能夠不必與源代碼打交道是最好的,因此我製作了一個Delphi的控制項TtablePro在Table的基礎上增加了兩個方法PackTable和Undelete;包含了上面介紹的功能。 *************************************************************************** 哈哈&兵燹
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-05-05 6:40:55
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!