数据库技术_Orcale技术(0004)_blob转换文件(图片、PDF、文本等与blob相互转换)


基础技术:

本文通过实例详细讲解blob和文件的相互转换和读写(包括图片、PDF、Word、文本等各种类型的文件),实例具体步骤如下:

1.创建路径

请参考:Oracle技术_UTL_FILE包用法详解_写出文件、读入库表 这篇文章中的第一节。

2.授权

请参考:Oracle技术_UTL_FILE包用法详解_写出文件、读入库表 这篇文章中的第二节。

3.写出Blob文件

通过查询库中blob内容,写出到指定服务器路径下,总体过程如下:

(1)通过UTL_FILE.FOPEN方法找到对应路径,创建文件,并且给出写入规则。

(2)通过DBMS_LOB.READ方法将Blob循环读到临时变量中,该变量就是要写到文件中的数据。

(3)通过UTL_FILE.PUT_RAW方法向文件中写入内容UTL_FILE.PUT_RAW方法是写入RAW类型的数据,一般来说RAW容量更大,用的更加广泛),同样采用循环方式分批写入。

(4)循环写入完成后,通过UTL_FILE.FCLOSE方法关闭文件,结束写出。
我们看一下具体操作,这里要创建一个存储过程GET_ALL_BLOB来演示该功能,具体看里面的注释。
代码如下:

CREATE OR REPLACE PROCEDURE GET_ALL_BLOB(I_ID VARCHAR2) IS
  L_FILE     UTL_FILE.FILE_TYPE;
  L_BUFFER   RAW(32676);
  L_AMOUNT   BINARY_INTEGER := 32676;
  L_POS      INTEGER := 1;
  L_BLOB     BLOB;
  L_BLOB_LEN INTEGER;
  L_FILENAME VARCHAR2(300);

BEGIN
  SELECT F.C_BLOB INTO L_BLOB FROM TEST_BLOB F WHERE F.C_ID = I_ID;
  SELECT F.C_NAME INTO L_FILENAME FROM TEST_BLOB F WHERE F.C_ID = I_ID;
  L_BLOB_LEN := DBMS_LOB.GETLENGTH(L_BLOB);
  L_FILE     := UTL_FILE.FOPEN('BLOB_FILE_DIR', L_FILENAME, 'wb');
  DBMS_OUTPUT.PUT_LINE('===OPEN OK===' || L_FILENAME || '===' ||
                       L_BLOB_LEN);
  WHILE L_POS < L_BLOB_LEN LOOP
    DBMS_OUTPUT.PUT_LINE('===LOOP OK===' || L_AMOUNT || '===' || L_POS);
    DBMS_LOB.READ(L_BLOB, L_AMOUNT, L_POS, L_BUFFER);
    DBMS_OUTPUT.PUT_LINE('===READ OK===' || LENGTH(L_BUFFER)); --不要随意用DBMS_OUTPUT.PUT_LINE打印L_BUFFER,因为L_BUFFER可能会很大,会出异常
    UTL_FILE.PUT_RAW(L_FILE, L_BUFFER, TRUE);
    DBMS_OUTPUT.PUT_LINE('===PUT OK===');
    L_POS    := L_POS + L_AMOUNT;
    L_BUFFER := '';
  END LOOP;
  DBMS_OUTPUT.PUT_LINE('EXPORT OK');
  UTL_FILE.FCLOSE(L_FILE);
EXCEPTION
  WHEN UTL_FILE.INVALID_PATH THEN
    --无效的路径
    DBMS_OUTPUT.PUT_LINE('===INVALID_PATH===' || I_ID);
    RAISE;
  WHEN UTL_FILE.INVALID_MODE THEN
    --无效的打开模式
    DBMS_OUTPUT.PUT_LINE('===INVALID_MODE===' || I_ID);
    RAISE;
  WHEN UTL_FILE.INVALID_OPERATION THEN
    --无效的操作,文件打开错误会报这个异常,一般来说都是超长或打开方式byte型和非byte型
    DBMS_OUTPUT.PUT_LINE('===INVALID_OPERATION===' || I_ID);
    RAISE;
  WHEN UTL_FILE.INVALID_MAXLINESIZE THEN
    --无效的最大长度,VARCHAR2最大4000,RAW最大32676,超过回报这个异常,所以一般要进行循环操作
    DBMS_OUTPUT.PUT_LINE('===INVALID_MAXLINESIZE===' || I_ID);
    RAISE;
  WHEN UTL_FILE.ACCESS_DENIED THEN
    --拒绝进入指定路径,可能是授权问题
    DBMS_OUTPUT.PUT_LINE('===ACCESS_DENIED===' || I_ID);
    RAISE;
  WHEN UTL_FILE.INVALID_FILEHANDLE THEN
    --文件处理错误,不常见
    DBMS_OUTPUT.PUT_LINE('===INVALID_FILEHANDLE===' || I_ID);
    RAISE;
  WHEN UTL_FILE.WRITE_ERROR THEN
    --写入错误,处理该异常最好的方式是将要写入的文件简单化,然后找准错误原因
    DBMS_OUTPUT.PUT_LINE('===WRITE_ERROR===' || I_ID);
    RAISE;
  WHEN NO_DATA_FOUND THEN
    --SELECT时候未找到数据,不是UTL_FILE的异常
    DBMS_OUTPUT.PUT_LINE('===NO_DATA_FOUND===' || I_ID);
    UTL_FILE.FCLOSE(L_FILE);
    RAISE;
  WHEN OTHERS THEN
    IF UTL_FILE.IS_OPEN(L_FILE) THEN
      UTL_FILE.FCLOSE(L_FILE);
      RAISE;
    END IF;
END GET_ALL_BLOB;

传入参数,调用该存储过程。
代码如下:

BEGIN
  -- Call the procedure
  GET_ALL_BLOB('ST2');
END;

执行后会在对应目录下生成文件(这里我blob里存的是图片),如下图:

数据库技术_Orcale技术(0004)_blob转换文件(图片、PDF、文本等与blob相互转换)_第1张图片

4.读入Blob文件

通过DBMS_LOB读取指定文件,将读取的内容写入库中的blob字段,总体过程如下:

(1)通过DBMS_LOB.FILEOPEN方法找到对应路径,读取文件(文件一定要存在,UTL_FILE不同的是,这里的文件类型为BFILE而不是UTL_FILE中的UTL_FILE.FILE_TYPE),并且给出读入规则,注意,我们这里不用UTL_FILE,而是用DBMS_LOB

(2)通过EMPTY_BLOB()把一个空的Blob对象INSERT到指定库表内,并将其RETURNING赋值给临时的Blob变量。

(3)通过DBMS_LOB.LOADFROMFILE方法循环向变量中写入内容(通过DBMS_LOB.GETLENGTH获取BFILE文件的大小),通过这种方式为Blob赋值非常简单,内部的处理都由DBMS_LOB.LOADFROMFILE处理

(4)写入完成后,通过DBMS_LOB.FILECLOSE方法关闭文件,结束读入。

我们看一下具体操作,这里要创建一个存储过程SET_ALL_BLOB来演示该功能,具体看里面的注释。

CREATE OR REPLACE PROCEDURE SET_ALL_BLOB(I_FILENAME VARCHAR2,
                                         I_ID       VARCHAR2) IS
  L_BFILE BFILE;
  L_BLOB  BLOB;
BEGIN
  L_BFILE := BFILENAME('BLOB_FILE_DIR', I_FILENAME);
  DBMS_LOB.FILEOPEN(L_BFILE);
  DBMS_OUTPUT.PUT_LINE('===OPEN OK===' || I_FILENAME);
  INSERT INTO TEST_BLOB F
    (C_ID, C_NAME, C_BLOB)
  VALUES
    (I_ID, I_FILENAME, EMPTY_BLOB())
  RETURNING C_BLOB INTO L_BLOB; --插入表
  DBMS_OUTPUT.PUT_LINE('===INSERT OK===' || I_FILENAME);
  DBMS_LOB.LOADFROMFILE(L_BLOB, L_BFILE, DBMS_LOB.GETLENGTH(L_BFILE));
  DBMS_OUTPUT.PUT_LINE('===LOADFROMFILE OK===' ||
                       DBMS_LOB.GETLENGTH(L_BFILE));
  DBMS_LOB.FILECLOSE(L_BFILE);
  DBMS_OUTPUT.PUT_LINE('EXPORT OK');
  COMMIT;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    --SELECT时候未找到数据,不是UTL_FILE的异常
    DBMS_OUTPUT.PUT_LINE('===NO_DATA_FOUND===' || I_ID);
    RAISE;
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('===OTHERS===' || I_ID);
    RAISE;
END SET_ALL_BLOB;

传入参数,调用该存储过程。

代码如下:

BEGIN
  -- Call the procedure
  SET_ALL_BLOB('Test_jpg.jpg', 'ST3');
END;

执行后会将文件内容存入表中,如下图:

数据库技术_Orcale技术(0004)_blob转换文件(图片、PDF、文本等与blob相互转换)_第2张图片


点击进入ooppookid的博客

你可能感兴趣的:(oracle,sql,存储过程,blob,utl_file)