熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Oracle >> 正文

Delphi中對Oracle存取RTF文檔

2013-11-13 22:10:47  來源: Oracle 

  關系數據庫都提供大文檔的存儲和提取對於視頻資料音頻資料圖象資料等大文檔一般需要另外開辟字段用於存儲摘要信息因此在查詢和檢索時並不訪問大字段而只是在存儲和提取時才操作 大字段例如你不能對Oracle中的LONG RAW類型進行LIKE介詞的查詢更不能使用等號 =查詢這對於存儲大段文本(容量超過K)同時又需要全文檢索是相當不便的本文將介紹如何利用數據庫的字符串數據類型存取和查詢大段文本這裡以Oracle數據庫和Delphi應用程序為例重點介紹如何在數據庫中存取 RTF文檔

  對於純文本可以簡單地將其分割成若干個串分別存儲到VARCHAR()字段中即可在查詢時可以使用LIKE比較從而達到全文檢索的目的為了保留換行等段落信息應當將回車換行(##)也作為串的一部分進行保存數據錄入時可以提供Memo控件(不是DBMemo)進行錄入然後順序連接各行當連接成的串臨近個字符(單字節字符)長度時就存入一條記錄然後對剩余的行重復上述操作這樣最終將純文本存成若干長度不超過的VARCHAR() 字段中這裡需要另外開辟字段 用於存儲文本編號和子序號以便區分不同的文本和讀取文本時順序連接所有的子串查詢純文本時就可以象查詢普通的VARCHAR 字段一樣可以使用LIKE也可以使用等號 =(幾乎不需要使用)需要注意的是可能用戶提供的關鍵字正好被存儲在不同的子串中這時是查詢不到的因此在設計時應當考慮存儲重復的串例如每個子串中僅有前 個字符是有效字符最後 個字符用於存儲 下一個子串的前 個字符這樣就避免了關鍵字被分開的情況唯一的不足是必須限制用戶輸入的查詢關鍵字長度不得超過 個字符(個漢字)但這很正常算不上不足

  事實上同樣可以利用這一技巧對 RTF文檔進行存取和查詢這時用於錄入和顯示 RTF文檔的是 RichEdit控件(不是DBRichEdit)而不再是Memo控件對於 RTF文檔的存取不能象存取純文本那樣通過Memo的屬性LinesStrings[Index]進行操作(盡管RichEdit控件具有相同的屬性)因為這樣做就無法保存文檔的格式了需要利用的是RichEdit的兩個方法SaveToFile和LoadFromFile需要了解的 是 RTF文件中用純字符描述字體字號文本等各種格式信息和內容信息因此存儲和提取時可以視為純文本進行操作但對於查詢就不能直接用LIKE加關鍵字的方式進行因為 RTF文檔中的每一個漢字都是用特殊的表示方法存儲只有單字節字符是原樣存儲所以在查詢時要對關鍵字進行處理才能 用在查詢語句中

  在測試這個例子之前必須有如下的數據結構這裡以Oracle創建表的 SQL語句形式給出

  (*
    CREATE TABLE TEST( { 表名為 TEST }
    DOCID NUMBER NOT NULL { 文檔編號 }
    DOCNAME VARCHAR() NOT NULL { 文檔標題 }
    SUBID NUMBER NOT NULL { 文檔子編號 }
    TEXT VARCHAR() NOT NULL { 子文檔內容 }
    PRIMARY KEY(DOCID SUBID)); { 聯合主鍵 }
    *) 下面是程序實例中的主要部分

  { }

  const
    BufSize = ; { 串的最大容量 }

  type
    TBuffer = array [BufSize] of Char; { 串緩存 }
    TFileOfChar = file of Char; { 字符類型文件 }

  TChnChar = string[]; { 漢字字符類型 }

  { SQL查詢返回首記錄首字段的值 }
    function SelectSQL(S: string): Variant;
    begin
    Result := NULL;
    with TADOQueryCreate(Application) do try
    Connection := FMainADOConnection;
    SQLAppend(S);
    SQLSaveToFile(c:\atxt);
    Open;
    Result := Fields[]AsVariant;
    finally
    Free;
    end;
    end;

  { 下面的函數將RTF文檔存入數據庫 }
    function RTFToDB(ARichEdit: TRichEdit; { 文檔容器 }
    DocName: string; { 文檔標題 }
    ATable: TADOTable { 操作的表 }
    ): Boolean; { 返回類型 }
    const
    TmpFileName = c:\xrtf; { 臨時文檔 }
    var
    DocID SubID L: Integer; { 局部變量 }
    S: string; { 串 }
    F: TFileOfChar; { 字符文件 }
    Buf: TBuffer; { 文本緩存 }
    begin
    ARichEditLinesSaveToFile(TmpFileName);{ 先存入文件 }
    AssignFile(F TmpFileName); { 打開文件 }
    Reset(F);
    try
    DocID := { 產生新的文檔編號 }
    SelectSQL(SELECT NVL(MAX(DOCID) + ) FROM TEST);
    with ATable do if not Active then Active := True;{ 確認表打開 }
    SubID := ; { 初始化子編號 }
    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\xrtf; { 臨時文件 }
    var
    S: string; { 局部串變量 }
    F: TFileOfChar; { 字符文件 }
    Buf: TBuffer; { 串緩存 }
    I L: Integer; { 局部變量 }
    begin
    ARichEditClear; { 清除當前顯示的內容 }
    AssignFile(F TmpFileName); { 關聯文件 }
    try
    Rewrite(F); { 打開文件准備寫入從數據庫讀出的數據 }
    with AQuery do begin
    Active := False; { 關閉數據集 }
    SQLClear; { 重建SQL語句 }
    SQLAppend(SELECT SUBID TEXT FROM TEST WHERE DOCNAME = +
    DocName + ORDER BY SUBID);
    Open; { 打開數據集 }
    if RecordCount <> then begin { 確認數據集非空 }
    First; { 移到首記錄子文檔 }
    repeat { 讀出一條子文檔並寫入文件 }
    S := FieldByName(TEXT)AsString;
    L := Length(S);
    for I := to L do Buf[I] := S[I];
    BlockWrite(F Buf L);
    Next;
    until EOF;
    end;
    end;
    CloseFile(F);{ 關閉文件 }
    ARichEditLinesLoadFromFile(TmpFileName);{ 從文件中裝入RTF文檔 }
    Result := True; { 讀取成功 }
    except { 讀取失敗 }
    try CloseFile(F); except end;
    Result := False;
    end;
    DeleteFile(TmpFileName); { 刪除臨時文件 }
    end;

  { 下面的函數將漢字單字轉換成RTF中表示的形式 }
    { 如表示漢字的是ASCII(b)和ASCII(fa)這裡是十六進制 }
    { 那麼在 RTF文件中對字的表示占用了 個字節 }
    { \b\fa }
    { 因此需要在查詢之前進行轉換由於表示方法中含有Delphi用於 }
    { 字符串的分解符單撇號因此在轉換時需要考慮這一點 }
    { 否則就不能構造出正確的 SQL查詢語句 }
    function ChnCharToRTFCode(Ch: TChnChar): string;
    var
    C C: Char;
    O O: Byte;
    S: string;
    begin
    C := Ch[];
    C := Ch[];
    O := Ord(C);
    O := Ord(C);
    S := Format(\%X [O]) + Format(\%X [O]);
    Result := Lowercase(S);{ 轉換為小寫 }
    end;

  { 根據需要檢索的關鍵字轉換成LIKE中使用的串 }
    { 這裡用於區別漢字的方法是根據編碼 }
    { 按照Windows 中的雙字節編碼規則對於雙字節字符 }
    { 如漢字字符是由兩個字節構成其中第一個字節是 }
    { 引導字符漢字引導字符的ASCII 碼大於 因此 }
    { 可以根據此特點來區分漢字和單字節字符 }
    function MakeLikeRTFString(StrToFind: string): string;
    var
    I: Integer;
    ChnChar: TChnChar;
    S: string;
    begin
    S := ;
    I := ;
    while I < Length(StrToFind) do begin
    Inc(I);
    if Integer(StrToFind[I]) >= $ then begin{ 漢字的首字節一定不小於 }
    ChnChar := StrToFind[I] + StrToFind[I + ];
    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;

  { }


From:http://tw.wingwit.com/Article/program/Oracle/201311/18394.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.