線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:1710
推到 Plurk!
推到 Facebook!

Delphi中對Oracle存取RTF文檔

 
jackkcg
站務副站長


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

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-01-08 11:49:54 IP:61.221.xxx.xxx 未訂閱
http://www.ccidnet.com/tech/guide/2001/06/07/58_2301.html Delphi中對Oracle存取RTF文檔 (蘇湧 2001年06月07日 21:39) 關聯資料庫都提供大文檔的存儲和提取。對於視頻資料、音頻資料、圖像資料等大文檔,一般需要 另外開闢欄位用於存儲摘要資訊,因此在查詢和檢索時並不訪問大欄位,而只是在存儲和提取時才操作 大欄位。例如,你不能對Oracle中的LONG RAW類型進行LIKE介詞的查詢,更不能使用等號“ =”查詢。 這對於存儲大段文本(容量超過2K)同時又需要全文檢索是相當不便的。本文將介紹如何利用資料庫的 字串資料類型存取和查詢大段文本。這裏以Oracle資料庫和Delphi應用程式?例,重點介紹如何在資料庫中存取 RTF文檔。 對於純文本,可以簡單地將其分割成若干個串,分別存儲到VARCHAR(2000)欄位中即可。在查詢時 可以使用LIKE比較,從而達到全文檢索的目的。?了保留換行等段落資訊,應當將回車換行(#13#10) 也作?串的一部分進行保存。資料錄入時可以提供Memo控制項(不是DBMemo)進行錄入,然後順序連接各行,當連接成的串臨近2000個字元(單字節字元)長度時,就存入一條記錄,然後對剩餘的行重復上述操作。這樣,最終將純文本存成若干長度不超過2000的VARCHAR(2000) 欄位中。這裏需要另外開闢欄位 用於存儲文本編號和子序號,以便區分不同的文本和讀取文本時順序連接所有的子串。查詢純文本時, 就可以象查詢普通的VARCHAR 欄位一樣,可以使用LIKE,也可以使用等號“ =”(幾乎不需要使用)。 需要注意的是,可能用戶提供的關鍵字正好被存儲在不同的子串中,這時是查詢不到的。因此,在設計時應當考慮存儲重復的串。例如,每個子串中僅有前1900個字元是有效字元,最後100 個字元用於存儲 下一個子串的前100 個字元。這樣就避免了關鍵字被分開的情況。唯一的不足是,必須限制用戶輸入的 查詢關鍵字長度不得超過100 個字元(50個漢字),但這很正常,算不上不足。 事實上,同樣可以利用這一技巧對 RTF文檔進行存取和查詢。這時,用於錄入和顯示 RTF文檔的是 RichEdit控制項(不是DBRichEdit),而不再是Memo控制項。對於 RTF文檔的存取,不能象存取純文本那樣 通過Memo的屬性Lines.Strings[Index]進行操作(儘管RichEdit控制項具有相同的屬性),因?這樣做就 無法保存文檔的格式了。需要利用的是RichEdit的兩個方法:SaveToFile和LoadFromFile。需要瞭解的 是, RTF文件中用純字元描述字體、字型大小、文本等各種格式資訊和內容資訊。因此,存儲和提取時可以 視?純文本進行操作。但對於查詢,就不能直接用LIKE加關鍵字的方式進行。因? RTF文檔中的每一個 漢字都是用特殊的表示方法存儲,只有單字節字元是原樣存儲。所以在查詢時要對關鍵字進行處理才能 用在查詢語句中。 在測試這個例子之前,必須有如下的資料結構,這裏以Oracle創建表的 SQL語句形式給出: (* CREATE TABLE TEST( { 表名? TEST } DOCID NUMBER NOT NULL, { 文檔編號 } DOCNAME VARCHAR(40) NOT NULL, { 文檔標題 } SUBID NUMBER NOT NULL, { 文檔子編號 } TEXT VARCHAR(2000) NOT NULL, { 子文檔內容 } PRIMARY KEY(DOCID, SUBID)); { 聯合主鍵 } *) 下面是程式實例中的主要部分: { ... ... } const BufSize = 2000; { 串的最大容量 } type TBuffer = array [1..BufSize] of Char; { 串緩存 } TFileOfChar = file of Char; { 字元類型文件 } TChnChar = string[2]; { 中文字元類型 } { SQL查詢,返回首記錄首欄位的值 } function SelectSQL(S: string): Variant; begin Result := NULL; with TADOQuery.Create(Application) do try Connection := FMain.ADOConnection1; SQL.Append(S); SQL.SaveToFile('c:\a.txt'); Open; Result := Fields[0].AsVariant; finally Free; end; end; { 下面的函數將RTF文檔存入資料庫 } function RTFToDB(ARichEdit: TRichEdit; { 文檔容器 } DocName: string; { 文檔標題 } ATable: TADOTable { 操作的表 } ): Boolean; { 返回類型 } const TmpFileName = 'c:\x.rtf'; { 臨時文檔 } var DocID, SubID, L: Integer; { 局部變數 } S: string; { 串 } F: TFileOfChar; { 字元文件 } Buf: TBuffer; { 文本緩存 } begin ARichEdit.Lines.SaveToFile(TmpFileName);{ 先存入文件 } AssignFile(F, TmpFileName); { 打開文件 } Reset(F); try DocID := { ?生新的文檔編號 } SelectSQL('SELECT NVL(MAX(DOCID) 1, 101) FROM TEST'); with ATable do if not Active then Active := True;{ 確認表打開 } SubID := 0; { 初始化子編號 } while not EOF(F) do begin Inc(SubID); BlockRead(F, Buf, BufSize, L); { 讀取兩千個字元 } S := Buf; SetLength(S, L); { 取實際讀取到的位元組數 } with ATable do begin { 增加一條子文檔 } Append; FieldByName('DOCID').AsInteger := DocID; FieldByName('DOCNAME').AsString := DocName; FieldByName('SubID').AsInteger := SubID; FieldByName('TEXT').AsString := S; Post; end; end; Result := True; { 存儲成功 } except Result := False;{ 存儲失敗 } end; CloseFile(F); { 關閉文件 } DeleteFile(TmpFileName);{ 刪除文件 } end; { 下面的函數從資料庫中讀取RTF文檔,並在指定的容器中顯示 } function RTFFromDB(ARichEdit: TRichEdit;{ RTF文檔容器 } DocName: string; { 文檔標題 } AQuery: TADOQuery { 操作的資料集 } ): Boolean; { 返回類型 } const TmpFileName = 'c:\temp\x.rtf'; { 暫存檔案 } var S: string; { 局部串變數 } F: TFileOfChar; { 字元文件 } Buf: TBuffer; { 串緩存 } I, L: Integer; { 局部變數 } begin ARichEdit.Clear; { 清除當前顯示的內容 } AssignFile(F, TmpFileName); { 關聯文件 } try Rewrite(F); { 打開文件,準備寫入從資料庫讀出的資料 } with AQuery do begin Active := False; { 關閉資料集 } SQL.Clear; { 重建SQL語句 } SQL.Append('SELECT SUBID, TEXT FROM TEST WHERE DOCNAME = ''' DocName ''' ORDER BY SUBID'); Open; { 打開資料集 } if RecordCount <> 0 then begin { 確認資料集非空 } First; { 移到首記錄-子文檔 } repeat { 讀出一條子文檔並寫入文件 } S := FieldByName('TEXT').AsString; L := Length(S); for I := 1 to L do Buf[I] := S[I]; BlockWrite(F, Buf, L); Next; until EOF; end; end; CloseFile(F);{ 關閉文件 } ARichEdit.Lines.LoadFromFile(TmpFileName);{ 從文件中裝入RTF文檔 } Result := True; { 讀取成功 } except { 讀取失敗 } try CloseFile(F); except end; Result := False; end; DeleteFile(TmpFileName); { 刪除暫存檔案 } end; { 下面的函數將漢字單字轉換成RTF中表示的形式。 } { 如表示漢字“國”的是ASCII(b9)和ASCII(fa),這裏是十六進位; } { 那?在 RTF文件中對“國”字的表示佔用了 8個位元組: } { \'b9\'fa } { 因此,需要在查詢之前進行轉換。由於表示方法中含有Delphi用於 } { 字串的分解符:單撇號“'”,因此在轉換時需要考慮這一點, } { 否則就不能構造出正確的 SQL查詢語句 } function ChnCharToRTFCode(Ch: TChnChar): string; var C1, C2: Char; O1, O2: Byte; S: string; begin C1 := Ch[1]; C2 := Ch[2]; O1 := Ord(C1); O2 := Ord(C2); S := Format('\''''%2X', [O1]) Format('\''''%2X', [O2]); Result := Lowercase(S);{ 轉換?小寫 } end; { 根據需要檢索的關鍵字轉換成LIKE中使用的串。 } { 這裏用於區別漢字的方法是根據編碼。 } { 按照Windows 中的雙位元組編碼規則,對於雙位元組字元 } { 如中文字元,是由兩個位元組構成,其中第一個位元組是 } { 引導字元。漢字引導字元的ASCII 碼大於 127,因此 } { 可以根據此特點來區分漢字和單字節字元。 } function MakeLikeRTFString(StrToFind: string): string; var I: Integer; ChnChar: TChnChar; S: string; begin S := ''; I := 0; while I < Length(StrToFind) do begin Inc(I); if Integer(StrToFind[I]) >= $80 then begin{ 漢字的首位元組一定不小於128 } ChnChar := StrToFind[I] StrToFind[I 1]; Inc(I); S := S ChnCharToRTFCode(ChnChar); end else begin{ 單字節字元 } S := S StrToFind[I]; if StrToFind[I] = '''' then S := S StrToFind[I];{ 單撇號的特殊處理 } end; end; Result := S; end; { 構造對關鍵字進行全文檢索的查詢語句 } function MakeLikeString(StrToFind: string): string; var S: string; begin S := MakeLikeRTFString(StrToFind); S := 'SELECT DISTINCT DOCNAME FROM TEST WHERE TEXT LIKE ''%' S '%'''; Result := S; end; { ... ... } *************************************************************************** 哈哈&兵燹 最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

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