Oracle中大對象(LOB)處理方法
目錄
- 一、LOB數(shù)據(jù)類型分類
- 1、按存儲數(shù)據(jù)的類型分
- 2、按存儲方式分
- 3、Null LOBs與Empty LOBs
- 二、LOB寫入
- 三、LOB讀取
- 四、BFile文件大對象(存儲在操作系統(tǒng)文件中的數(shù)據(jù))
- 1. 創(chuàng)建
- 2. 讀取
- 五、將文件系統(tǒng)數(shù)據(jù)庫通過BFile導(dǎo)入到LOB字段中
- 六、C#讀寫Oracle BOLB數(shù)據(jù)。
- (1)寫入數(shù)據(jù)到Orable Blob字段中。
- (2)讀取Oracle Blob到文件中。
一、LOB數(shù)據(jù)類型分類
1、按存儲數(shù)據(jù)的類型分
- 字符類型:
CLOB:存儲大量 單字節(jié) 字符數(shù)據(jù)。
NLOB:存儲定寬 多字節(jié) 字符數(shù)據(jù)。 - 二進(jìn)制類型:
BLOB:存儲較大無結(jié)構(gòu)的二進(jìn)制數(shù)據(jù)。 - 二進(jìn)制文件類型:
BFILE:將二進(jìn)制文件存儲在數(shù)據(jù)庫外部的操作系統(tǒng)文件中。存放文件路徑。
2、按存儲方式分
- 存儲在內(nèi)部表空間:
CLOB,NLOB和BLOB - 指向外部操作系統(tǒng)文件:
BFILE
3、Null LOBs與Empty LOBs
DECLARE some_clob CLOB; BEGIN IF some_clob IS NULL THEN dbms_output.put_line("a"); --NULL 表示該 LOB 字段或變量中連 LOB 指針都沒有 ELSIF dbms_lob.getlength(some_clob) = 0 THEN dbms_output.put_line("b"); --empty LOB 是指該 LOB 字段或變量中保存了一個 LOB 指針,但這個指針并沒有指向任何 LOB 數(shù)據(jù) ELSE dbms_output.put_line("c"); --指針有實際內(nèi)容 END IF; END;
二、LOB寫入
Blob數(shù)據(jù)不能象其它類型數(shù)據(jù)一樣直接插入(INSERT)。插入前必須先插入一個空的Blob對象,BLOB類型的空對象為EMPTY_BLOB(),之后通過SELECT命令查詢得到先前插入的記錄并鎖定,繼而將空對象修改為所要插入的Blob對象。
當(dāng)獲取到一個可用的 LOB 指針(定位器)后,就可以通過該指針寫入 LOB 數(shù)據(jù)了。有兩種寫入數(shù)據(jù)的系統(tǒng)函數(shù):
- DBMS_LOB.WRITE :將數(shù)據(jù)隨機(jī)地寫入 LOB 中。
- DBMS_LOB.WRITEAPPEND :從 LOB 的最后開始寫入數(shù)據(jù)。
運(yùn)用dbms_lob包用dbms_lob.write()寫入只能存儲32k以下的圖片。
注意:這里并不需要使用 UPDATE 來更新列 falls_myclob,因為這個 LOB 指針并沒有發(fā)生變化,我們只是將數(shù)據(jù)寫入它所指向的位置。
declare myclob clob; amount binary_integer; offset integer; first_direction varchar2(100); more_myclob varchar2(500); begin --刪除所有“munining Falls”的現(xiàn)有行,然后 delete from waterfalls where falls_name = "Munising Falls"; insert into waterfalls (falls_name, falls_myclob) values ("Munising Falls", EMPTY_CLOB()); --使用EMPTY_CLOB()插入新行來創(chuàng)建LOB定位器 select falls_myclob into myclob from waterfalls where falls_name = "Munising Falls"; --檢索由前面的INSERT語句創(chuàng)建的LOB定位器 --或直接 INSERT into waterfalls(falls_name, falls_myclob) values("Munising Falls" EMPTY_CLOB()); returning falls_myclob into myclob; DBMS_LOB.OPEN(myclob, DBMS_LOB.LOB_READWRITE); --打開LOB;不是嚴(yán)格必要的,但是最好打開/關(guān)閉lob。 first_direction := "Follow I-75 across the Mackinac Bridge."; amount := LENGTH(first_direction); --要寫的字符數(shù) offset := 1; --開始寫CLOB的第一個字符 DBMS_LOB.WRITE(myclob, amount, offset, first_direction); --使用DBMS_LOB。開始寫 more_myclob := " Take US-2 west from St. Ignace to Blaney Park." || " From Seney, take M-28 west to Munising."; --使用DBMS_LOB.WRITEAPPEND添加更多的myclob DBMS_LOB.WRITEAPPEND(myclob, LENGTH(more_myclob), more_myclob); more_myclob := " In front of the paper mill, turn right on H-58." || " Sand Point Road."; --添加更多的myclob DBMS_LOB.WRITEAPPEND(myclob, LENGTH(more_myclob), more_myclob); DBMS_LOB.CLOSE(myclob); --關(guān)閉LOB,就完成了。 end;
三、LOB讀取
使用系統(tǒng)函數(shù) DBMS_LOB.READ( ) 來讀取 LOB 中的數(shù)據(jù),當(dāng)然,首先要得到這個 LOB 指針。比如讀取 CLOB 數(shù)據(jù),應(yīng)該指定字符串的偏移量(offset),從指定的偏移量的位置開始讀取數(shù)據(jù)。
CLOB 的第一個字符的偏移量是1;也需要指定讀取的字符串長度。如果這個 CLOB 數(shù)據(jù)太大,應(yīng)該多次讀取數(shù)據(jù)。對于 BLOB 數(shù)據(jù),也是這樣處理,唯一的區(qū)別就是它是按字節(jié)存儲的。
DBMS_LOB.READ 中的第二個參數(shù) chars_read_1,是 IN OUT 參數(shù)。
調(diào)用時按照該參數(shù)指定的長度來讀取數(shù)據(jù),讀取完畢后,將其更新為實際讀取的字符(字節(jié))長度。
當(dāng)讀取后,該參數(shù)的值比你原來的值小,則說明已經(jīng)讀取到 LOB 的末尾了。
declare myclob clob; myclob_1 varchar2(300); myclob_2 varchar2(300); chars_read_1 binary_integer; chars_read_2 binary_integer; offset integer; begin select falls_myclob into myclob from waterfalls where falls_name = "Munising Falls"; --檢索之前插入的LOB定位器 offset := 1; --從第一個字符開始閱讀 chars_read_1 := 229; --嘗試讀取myclob的229個字符時,chars_read_1將使用實際讀取的字符數(shù)進(jìn)行更新 DBMS_LOB.READ(myclob, chars_read_1, offset, myclob_1); if chars_read_1 = 229 then --如果讀取229個字符,則更新偏移量并嘗試讀取255個字符。 offset := offset + chars_read_1; chars_read_2 := 255; DBMS_LOB.READ(myclob, chars_read_2, offset, myclob_2); else chars_read_2 := 0; myclob_2 := ""; end if; DBMS_OUTPUT.PUT_LINE("Characters read = " || TO_CHAR(chars_read_1 + chars_read_2)); --顯示讀取的字符總數(shù) DBMS_OUTPUT.PUT_LINE(myclob_1); --顯示myclob DBMS_OUTPUT.PUT_LINE(myclob_2); end;
四、BFile文件大對象(存儲在操作系統(tǒng)文件中的數(shù)據(jù))
PL/SQL中的Bfile只能讀取Bfile數(shù)據(jù),而不能寫入。
BLOB,CLOB,NCLOB 存儲在數(shù)據(jù)庫內(nèi),而 BFILE 存儲在數(shù)據(jù)庫外。BFILE 和其他三種大字段類型相比,BFILE 有以下三點不同:
- BFILE 的數(shù)據(jù)是存儲在操作系統(tǒng)文件中的,而不是在數(shù)據(jù)庫中;
- BFILE 數(shù)據(jù)不參與事務(wù)處理,也就是說,BFILE 數(shù)據(jù)的改變不能被提交和回滾(但 BFILE 指針的改變是可以提交或回滾的);
- 從 PL/SQL 中,只能讀取 BFILE 數(shù)據(jù),而不能寫入。必須得在數(shù)據(jù)庫外先創(chuàng)建 BFILE 文件,再創(chuàng)建 BFILE 指針。
在 PL/SQL 中操作 BFILE,其實也是操作 LOB 指針。只是對于 BFILE 的指針來說,它指向的 BFILE 數(shù)據(jù)在數(shù)據(jù)庫外。
所以,一個 BFILE 列的兩行,可以存儲指向同一個文件的 BFILE 指針。
1. 創(chuàng)建
BFILE 指針由目錄(Oracle服務(wù)器上)和文件名組成(而實際的目錄和文件可以不存在),將這兩部分信息作為參數(shù)傳入 BFILENAME 函數(shù),該函數(shù)會返回一個 BFILE 指針。
create directory BFILE_DATA as "D:/temp"; declare waterfall_picture bfile; begin waterfall_picture := BFILENAME("BFILE_DATA","waterfall.gif"); --調(diào)用BFILENAME來創(chuàng)建BFILE定位器 insert into waterfalls (falls_name, falls_web_page) values ("my waterfall",waterfall_picture); --保存我們的新定位在waterfalls en
2. 讀取
declare waterfall bfile; piece raw(60); amount binary_integer := 60; offset integer := 1; begin select falls_web_page into waterfall from waterfalls where falls_name="my waterfall"; --檢索LOB定位器 DBMS_LOB.OPEN(waterfall); --打開定位器,讀取60個字節(jié),然后關(guān)閉定位器 DBMS_LOB.READ(waterfall, amount, 1, piece); DBMS_LOB.CLOSE(waterfall); DBMS_OUTPUT.PUT_LINE(RAWTOHEX(piece));--十六進(jìn)制顯示結(jié)果 --將原始結(jié)果轉(zhuǎn)換為我們可以讀取的字符串 --DBMS_OUTPUT.PUT_LINE(UTL_RAW.CAST_TO_VARCHAR2(piece)); end;
五、將文件系統(tǒng)數(shù)據(jù)庫通過BFile導(dǎo)入到LOB字段中
BFILE 提供了一種從數(shù)據(jù)庫中訪問文件系統(tǒng)中數(shù)據(jù)的方法。可能你想將這些數(shù)據(jù)保存到 BLOB 或 CLOB 字段中。
可以使用系統(tǒng)函數(shù)實現(xiàn):
- dbms_lob.loadfrombfile
- dbms_lob.loadclobfrombfile
- dbms_lob.loadblobfrombfile
下面我們將圖片 watarfall.gif 保存到 BLOB 列中:
declare My_Falls_bfile bfile := BFILENAME("BFILE_DATA", "waterfall.gif"); photo blob; destination_offset integer := 1; source_offset integer := 1; begin delete from waterfalls where falls_name = "my waterfall"; --刪除Tannery Falls的行,所以這個例子可以運(yùn)行多次。 insert into waterfalls (falls_name, FALLS_PHOTO) values ("my waterfall", EMPTY_BLOB());--使用EMPTY_BLOB()插入新行來創(chuàng)建LOB定位器 select FALLS_PHOTO into photo from waterfalls where falls_name = "my waterfall"; --檢索由前面的INSERT語句創(chuàng)建的LOB定位器 DBMS_LOB.OPEN(photo, DBMS_LOB.LOB_READWRITE);--打開目標(biāo)BLOB和源BFILE DBMS_LOB.OPEN(My_Falls_bfile); DBMS_LOB.LOADBLOBFROMFILE(photo, My_Falls_bfile, DBMS_LOB.LOBMAXSIZE, destination_offset, source_offset); --Load the contents of the BFILE into the BLOB column DBMS_LOB.CLOSE(photo); --關(guān)閉兩個lob DBMS_LOB.CLOSE(My_Falls_bfile); end;
六、C#讀寫Oracle BOLB數(shù)據(jù)。
(1)寫入數(shù)據(jù)到Orable Blob字段中。
首先要在BLob字段中插入一個Empty_blob(),才能寫入下面的數(shù)據(jù)。
* 在調(diào)用此函數(shù)之前需要寫插入一個字符串到 BLOB 中比如: *"CREATE TABLE tablewithlobs (a int, b BLOB, c CLOB, d NCLOB)"; *"INSERT INTO tablewithlobs values (1, "AA", "AAA", N"AAAA")"; * 否則程序會在 OracleLob tempLob = reader.GetOracleLob(0) 處出錯。
寫入:
conn.Open(); OracleCommand cmd = conn.CreateCommand(); OracleTransaction transaction = cmd.Connection.BeginTransaction(); // 利用事務(wù)處理(必須) cmd.Transaction = transaction; // 獲得 OracleLob 指針 cmd.CommandText = "select fulls_myblob from waterfalls where fulls_name = "myabc" FOR UPDATE"; using (OracleDataReader reader = cmd.ExecuteReader()) { reader.Read(); //Obtain the first row of data. OracleBlob tempLob = reader.GetOracleBlobForUpdate(0); //Obtain a LOB. FileStream fs = new FileStream("c:\\1.txt", FileMode.Open); // 將文件寫入 BLOB 中 tempLob.BeginChunkWrite(); int length = 10485760; byte[] Buffer = new byte[length]; int i; while ((i = fs.Read(Buffer, 0, length)) > 0) { tempLob.Write(Buffer, 0, i); } fs.Close(); tempLob.EndChunkWrite(); cmd.Parameters.Clear(); } transaction.Commit(); // 提交事務(wù) conn.Close();
(2)讀取Oracle Blob到文件中。
conn.Open(); OracleCommand cmd = conn.CreateCommand(); OracleTransaction trans = cmd.Connection.BeginTransaction();// 利用事務(wù)處理(必須) cmd.Transaction = trans; // 獲得 OracleLob 指針 string sql = "select fulls_myblob from waterfalls where fulls_name = "myabc""; cmd.CommandText = sql; OracleDataReader dr = cmd.ExecuteReader(); dr.Read(); OracleBlob tempLob = dr.GetOracleBlob(0); dr.Close(); // 讀取 BLOB 中數(shù)據(jù),寫入到文件中 FileStream fs = new FileStream("c:\\1.txt", FileMode.Create); int length = 1048576; byte[] Buffer = new byte[length]; int i; while ((i = tempLob.Read(Buffer, 0, length)) > 0) { fs.Write(Buffer, 0, i); } fs.Close(); tempLob.Clone(); cmd.Parameters.Clear(); trans.Commit(); // 提交事務(wù) conn.Close();
到此這篇關(guān)于Oracle中大對象(LOB)處理方法的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持。
相關(guān)文章:
1. Oracle數(shù)據(jù)庫編寫有效事務(wù)指導(dǎo)方針2. Oracle PL/SQL語言初級教程之操作和控制語言3. Oracle 10g(10.1.0.2)中的OPTIMIZER_INDEX_COST_ADJ4. Oracle數(shù)據(jù)庫經(jīng)典優(yōu)化之索引原理篇5. 基于已被證實的Oracle高可用性技術(shù)MAA6. Oracle多行記錄字符串綜合操作幾種方法7. 審計并報告Oracle數(shù)據(jù)庫中用戶活動8. oracle中用Create Table創(chuàng)建表時,Storage中參數(shù)的含義!9. Oracle縮表空間的完整解決實例10. oracle分區(qū)表學(xué)習(xí)及應(yīng)用
