我们先前
介绍过,BLOB,CLOB,NCLOB 存储在数据库内,而 BFILE 存储在数据库外。和其他三种大字段类型相比,BFILE 有以下三点不同:
* BFILE 的数据是存储在操作系统文件中的,而不是在数据库中;
* BFILE 数据不参与事务处理,也就是说,BFILE 数据的改变不能被提交和回滚(但 BFILE 指针的改变是可以提交或回滚的);
* 从 PL/SQL 中,只能读取 BFILE 数据,而不能写入。必须得在数据库外先创建 BFILE 文件,再创建 BFILE 指针。
在 PL/SQL 中操作 BFILE,其实也是操作 LOB 指针。只是对于 BFILE 的指针来说,它指向的 BFILE 数据在数据库外。所以,一个 BFILE 列的两行,可以存储指向同一个文件的 BFILE 指针。
1. 创建
BFILE 指针由目录和文件名组成,将这两部分信息作为参数传入 BFILENAME 函数,该函数会返回一个 BFILE 指针。
例如,我要将存储于 D 盘中的图片 waterfall.gif 以 BFILE 的形式保存到数据库中:
D:/temp>dir wat*
驱动器 D 中的卷是 D 卷的序列号是 15C2-D261
D:/temp 的目录
2008-06-06 11:08 56,073 waterfall.gif
1 个文件 56,073 字节 0 个目录 7,558,959,104 可用字节 |
那么首先,我应该创建一个目录:
SQL> create directory bfile_data as 'D:/temp';
目录已创建。
|
然后,通过很简单的调用 BFILENAME 函数,即可将 BIFLE 指针保存到表中:
SQL> DECLARE
2 waterfall_picture BFILE; 3 BEGIN 4 --Invoke BFILENAME to create a BFILE locator 5 waterfall_picture := BFILENAME('BFILE_DATA','waterfall.gif'); 6 7 --Save our new locator in the waterfalls table 8 INSERT INTO waterfalls (falls_name, falls_web_page) 9 VALUES ('my waterfall',waterfall_picture); 10 END; 11 /
PL/SQL 过程已成功完成。
|
这里是可以提交和回滚的,因为这里发生改变的是 BFILE 指针,而不是 BFILE 数据。
一个 BFILE 指针只是简单地将目录和文件名联合在一块,而实际的目录和文件甚至可以不存在。所以,你可以创建一个目录,它实际指向的路径并不存在;再使用这个目录创建一个 BFILE 指针。很多时候,这种功能使得我们编程很方便。
2. 读取
BFILE 数据的读取,与我们前面介绍的其他 LOB 类型的读取方式是一样的。
SQL> DECLARE
2 waterfall BFILE; 3 piece RAW(60); 4 amount BINARY_INTEGER := 60; 5 offset INTEGER := 1; 6 BEGIN 7 --Retrieve the LOB locator 8 SELECT falls_web_page 9 INTO waterfall 10 FROM waterfalls 11 WHERE falls_name='my waterfall'; 12 13 --Open the locator, read 60 bytes, and close the locator 14 DBMS_LOB.OPEN(waterfall); 15 DBMS_LOB.READ(waterfall, amount, 1, piece); 16 DBMS_LOB.CLOSE(waterfall); 17 18 --Display results in hex 19 DBMS_OUTPUT.PUT_LINE(RAWTOHEX(piece)); 20 21 --Cast RAW results to a character string we can read 22 --DBMS_OUTPUT.PUT_LINE(UTL_RAW.CAST_TO_VARCHAR2(piece)); 23 END; 24 / 474946383961CF01320277003121FE1A536F6674776172653A204D6963726F736F6674204F666669 63650021F90401000000002C00000000CE013102
PL/SQL 过程已成功完成。
|
在一个会话中,可以打开的文件总数受参数 session_max_open_files 限制,该参数同时限制了使用其他方式打开的文件数(比如使用 UTL_FILE 包打开的文件数):
SQL> show parameter session_max
NAME TYPE VALUE
------------------------------------ ----------- ----- session_max_open_files integer 10 |
在 Oracle 中,对 BFILE 数据只能做读操作。比如你用数码相机照了一些照片,并将它们上传到你的电脑上了。那么,你可以使用 BFILE 类型,在数据库中创建对应的 BFILE 指针,这样,你就可以在 PL/SQL 代码中访问它们了。
3. 从 BFILE 到 LOB
BFILE 提供了一种从数据库中访问文件系统中数据的方法。可能你想将这些数据保存到 BLOB 或 CLOB 字段中。从 Oracle9i Database Release 1 开始,可以使用系统函数 DBMS_LOB.LOADFROMBFILE 实现;从 Oracle9i Database Release 2 开始,又提供了两个函数
* DBMS_LOB.LOADCLOBFROMBFILE:从 BFILE 数据中获取 CLOB 数据(注意字符集的转换)。
* DBMS_LOB.LOADBLOBFROMBFILE:从 BFILE 数据中获取 BLOB 数据。功能和 DBMS_LOB.LOADFROMBFILE 一样,只是为了统一而提供的函数。
下面我们将图片 watarfall.gif 保存到 BLOB 列中:
SQL> DECLARE
2 My_Falls_Directions BFILE := BFILENAME('BFILE_DATA','waterfall.gif'); 3 photo BLOB; 4 destination_offset INTEGER := 1; 5 source_offset INTEGER := 1; 6 language_context INTEGER := DBMS_LOB.default_lang_ctx; 7 warning_message INTEGER; 8 BEGIN 9 --Delete row for Tannery Falls, so this example 10 --can run multiple times. 11 DELETE FROM waterfalls WHERE falls_name='my waterfall'; 12 13 --Insert a new row using EMPTY_BLOB( ) to create a LOB locator 14 INSERT INTO waterfalls 15 (falls_name,FALLS_PHOTO) 16 VALUES ('my waterfall',EMPTY_BLOB( )); 17 18 --Retrieve the LOB locator created by the previous INSERT statement 19 SELECT FALLS_PHOTO 20 INTO photo 21 FROM waterfalls 22 WHERE falls_name='my waterfall'; 23 24 --Open the target BLOB and the source BFILE 25 DBMS_LOB.OPEN(photo, DBMS_LOB.LOB_READWRITE); 26 DBMS_LOB.OPEN(My_Falls_Directions); 27 28 --Load the contents of the BFILE into the BLOB column 29 DBMS_LOB.LOADBLOBFROMFILE(photo, My_Falls_Directions, 30 DBMS_LOB.LOBMAXSIZE, 31 destination_offset, source_offset); 32 33 --Close both LOBs 34 DBMS_LOB.CLOSE(photo); 35 DBMS_LOB.CLOSE(My_Falls_Directions); 36 END; 37 /
PL/SQL 过程已成功完成。
|