Oracle中大对象(LOB)处理方法

2022-07-15,,,,

一、lob数据类型分类

1、按存储数据的类型分

  • 字符类型: 
    clob:存储大量 单字节 字符数据。 
    nlob:存储定宽 多字节 字符数据。
  • 二进制类型: 
    blob:存储较大无结构的二进制数据。
  • 二进制文件类型: 
    bfile:将二进制文件存储在数据库外部的操作系统文件中。存放文件路径。

2、按存储方式分

  • 存储在内部表空间: 
    clob,nlob和blob
  • 指向外部操作系统文件: 
    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 数据
    else
        dbms_output.put_line('c'); --指针有实际内容
    end if;
end;

二、lob写入

blob数据不能象其它类型数据一样直接插入(insert)。插入前必须先插入一个空的blob对象,blob类型的空对象为empty_blob(),之后通过select命令查询得到先前插入的记录并锁定,继而将空对象修改为所要插入的blob对象。

当获取到一个可用的 lob 指针(定位器)后,就可以通过该指针写入 lob 数据了。有两种写入数据的系统函数:

  • dbms_lob.write :将数据随机地写入 lob 中。
  • dbms_lob.writeappend :从 lob 的最后开始写入数据。

运用dbms_lob包用dbms_lob.write()写入只能存储32k以下的图片。

注意:这里并不需要使用 update 来更新列 falls_myclob,因为这个 lob 指针并没有发生变化,我们只是将数据写入它所指向的位置。

declare
  myclob          clob;
  amount          binary_integer;
  offset          integer;
  first_direction varchar2(100);
  more_myclob     varchar2(500);
begin
  --删除所有“munining falls”的现有行,然后
  delete from waterfalls   where falls_name =      'munising falls';
  
  insert into waterfalls   (falls_name, falls_myclob)  values   ('munising falls', empty_clob()); --使用empty_clob()插入新行来创建lob定位器
  select falls_myclob   into myclob   from waterfalls  where falls_name = 'munising falls'; --检索由前面的insert语句创建的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;不是严格必要的,但是最好打开/关闭lob。
  
  first_direction := 'follow i-75 across the mackinac bridge.';
  amount          := length(first_direction); --要写的字符数
  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); --关闭lob,就完成了。
end;

三、lob读取

使用系统函数 dbms_lob.read( ) 来读取 lob 中的数据,当然,首先要得到这个 lob 指针。比如读取 clob 数据,应该指定字符串的偏移量(offset),从指定的偏移量的位置开始读取数据。 
clob 的第一个字符的偏移量是1;也需要指定读取的字符串长度。如果这个 clob 数据太大,应该多次读取数据。对于 blob 数据,也是这样处理,唯一的区别就是它是按字节存储的。 
dbms_lob.read 中的第二个参数 chars_read_1,是 in out 参数。 
调用时按照该参数指定的长度来读取数据,读取完毕后,将其更新为实际读取的字符(字节)长度。 
当读取后,该参数的值比你原来的值小,则说明已经读取到 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将使用实际读取的字符数进行更新
  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));  --显示读取的字符总数
  dbms_output.put_line(myclob_1);  --显示myclob
  dbms_output.put_line(myclob_2);
end;

四、bfile文件大对象(存储在操作系统文件中的数据)

pl/sql中的bfile只能读取bfile数据,而不能写入。

blob,clob,nclob 存储在数据库内,而 bfile 存储在数据库外。bfile 和其他三种大字段类型相比,bfile 有以下三点不同:

  • bfile 的数据是存储在操作系统文件中的,而不是在数据库中;
  • bfile 数据不参与事务处理,也就是说,bfile 数据的改变不能被提交和回滚(但 bfile 指针的改变是可以提交或回滚的);
  • 从 pl/sql 中,只能读取 bfile 数据,而不能写入。必须得在数据库外先创建 bfile 文件,再创建 bfile 指针。

在 pl/sql 中操作 bfile,其实也是操作 lob 指针。只是对于 bfile 的指针来说,它指向的 bfile 数据在数据库外。 
所以,一个 bfile 列的两行,可以存储指向同一个文件的 bfile 指针。

1. 创建

bfile 指针由目录(oracle服务器上)和文件名组成(而实际的目录和文件可以不存在),将这两部分信息作为参数传入 bfilename 函数,该函数会返回一个 bfile 指针。

create directory bfile_data as 'd:/temp';
declare
 waterfall_picture bfile;
begin
 waterfall_picture := bfilename('bfile_data','waterfall.gif'); --调用bfilename来创建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个字节,然后关闭定位器
 dbms_lob.read(waterfall, amount, 1, piece);
 dbms_lob.close(waterfall);

 dbms_output.put_line(rawtohex(piece));--十六进制显示结果
 --将原始结果转换为我们可以读取的字符串
 --dbms_output.put_line(utl_raw.cast_to_varchar2(piece));
 end;

五、将文件系统数据库通过bfile导入到lob字段中

bfile 提供了一种从数据库中访问文件系统中数据的方法。可能你想将这些数据保存到 blob 或 clob 字段中。 
可以使用系统函数实现:

  • 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的行,所以这个例子可以运行多次。
  insert into waterfalls (falls_name, falls_photo) values ('my waterfall', empty_blob());--使用empty_blob()插入新行来创建lob定位器
  select falls_photo into photo from waterfalls where falls_name = 'my waterfall'; --检索由前面的insert语句创建的lob定位器
  dbms_lob.open(photo, dbms_lob.lob_readwrite);--打开目标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);  --关闭两个lob
  dbms_lob.close(my_falls_bfile);
end;

六、c#读写oracle bolb数据。

(1)写入数据到orable blob字段中。

首先要在blob字段中插入一个empty_blob(),才能写入下面的数据。

* 在调用此函数之前需要写插入一个字符串到 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();      // 利用事务处理(必须)
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(); // 提交事务
conn.close();

(2)读取oracle blob到文件中。

conn.open();
oraclecommand cmd = conn.createcommand();
oracletransaction trans = cmd.connection.begintransaction();// 利用事务处理(必须)
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 中数据,写入到文件中
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();     // 提交事务
conn.close();

到此这篇关于oracle中大对象(lob)处理方法的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持。

《Oracle中大对象(LOB)处理方法.doc》

下载本文的Word格式文档,以方便收藏与打印。