1

我正在使用以下函数将大型 base64 编码文件(图像或语音)转换为 blob 文件并将其存储在 Oracle 数据库中(Oracle 数据库 11g 企业版版本 11.1.0.7.0 - 生产)。

我能够存储和检索它,但图像已损坏。仅检索到图像的一部分。我尝试使用小图像(11KB 大小),它工作正常。但是对于较大的图像(88KB 到 700KB),只检索图像的一部分。

问题在于base-64解码。早些时候,由于损坏,我什至无法获得更小的图像,但是当我增加缓冲区大小时,它就很好了。现在缓冲区大小的最大值为 32767,这是 varchar2 和 raw 的最大值。

任何人都可以提供合适的解决方法或解决方案。

function decode_base64(p_clob_in in clob) return blob is
    v_blob blob;
    v_result blob;
    v_offset integer;
    v_buffer_size binary_integer := 32767;     -- 24, 48, 3072
    v_buffer_varchar varchar2(32767);
    v_buffer_raw raw(32767);

  begin

    if p_clob_in is null then
      return null;
    end if;

    dbms_lob.createtemporary(v_blob, true);
    v_offset := 1;

    for i in 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size) 
    loop
      dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
      v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
      v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
      dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
      v_offset := v_offset + v_buffer_size;
    end loop;

    v_result := v_blob;
    dbms_lob.freetemporary(v_blob);

    return v_result;

  end decode_base64;

我用来调用函数并将 blob 插入表中的代码如下所示......

 PROCEDURE create_notes (
      p_task_id              IN       NUMBER
     ,p_note_title           IN       VARCHAR2
     ,p_note_detail          IN       VARCHAR2
     ,p_attach_name          IN       VARCHAR2
     ,p_attachment           IN       CLOB
     ,p_attach_type          IN       VARCHAR2
     ,x_return_code          OUT      VARCHAR2
     ,x_return_message       OUT      VARCHAR2
   )
IS
  l_blob_data BLOB;
BEGIN
.
.
.
 IF p_attachment IS NOT NULL THEN


            SELECT incident_id INTO l_pk1_value FROM csf_ct_tasks where task_id = p_task_id;

                        l_blob_data :=  xx_utl_base64.decode_base64(p_attachment);
INSERT INTO fnd_lobs
                        (file_id, file_name, file_content_type, upload_date,
                        expiration_date, program_name, program_tag, file_data,
                        LANGUAGE, oracle_charset, file_format
                        )
                        VALUES (l_media_id, p_attach_name,p_attach_type,  -- 'audio/mpeg','application/pdf','image/jpeg'
                        SYSDATE,
                        NULL, 'FNDATTCH', NULL, l_blob_data,               --l_blob_data,EMPTY_BLOB ()
                        'US', 'UTF8', 'binary'
                        )
                        RETURNING file_data
                        INTO x_blob;
COMMIT;
END IF:

下面附上原始图片及其解码版本。原图

解码图像

4

3 回答 3

2

我从网上得到了下面的代码。它就像一个魅力。不知道我的旧代码有什么问题。

 FUNCTION base64decode(p_clob CLOB)
         RETURN BLOB

        IS
         l_blob    BLOB;
         l_raw     RAW(32767);
         l_amt     NUMBER := 7700;
         l_offset  NUMBER := 1;
         l_temp    VARCHAR2(32767);
        BEGIN
         BEGIN
           DBMS_LOB.createtemporary (l_blob, FALSE, DBMS_LOB.CALL);
           LOOP
             DBMS_LOB.read(p_clob, l_amt, l_offset, l_temp);
             l_offset := l_offset + l_amt;
             l_raw    := UTL_ENCODE.base64_decode(UTL_RAW.cast_to_raw(l_temp));
             DBMS_LOB.append (l_blob, TO_BLOB(l_raw));
           END LOOP;
         EXCEPTION
           WHEN NO_DATA_FOUND THEN
             NULL;
         END;
         RETURN l_blob;
        END;
于 2013-10-25T12:48:13.570 回答
1

我用 8192 的 v_buffer_size 尝试了你的函数,它运行良好。我已经尝试了几个小于 32767 的数字,它们都运行良好,所以尝试一些小于 32767 的数字。

于 2013-10-23T15:16:21.017 回答
0

对于那些仍在寻找正确解决方案的人 - 您需要以 4 的倍数解码输入数据。如果输入包含非 base64 符号(被内置函数忽略utl_encode.base64_decode),可能会导致大文件的结果不正确。

我在网上发现了很多不能正确解码的样本,把我的代码贴在下面

    函数 base64_decode(p_content CLOB) 返回 BLOB
    是
        C_CHUNK_SIZE 常量整数:= 12000;-- 应该是 4 的倍数
        C_NON_BASE64_SYM_PATTERN CONSTANT VARCHAR2(20) := '[^A-Za-z0-9+/]';
        l_chunk_buf VARCHAR2(12000);
        l_chunk_b64_buf RAW(9000);
        l_chunk_offset 整数:= 1;
        l_chunk_size 整数;
        l_res BLOB;

        FUNCTION get_next_full_base64_chunk(l_data CLOB, p_cur_pos IN OUT INTEGER, p_desired_size INTEGER, p_cur_size IN OUT INTEGER) RETURN VARCHAR2 IS
            l_res VARCHAR2(12000);
            l_tail_desired_size 整数;
        开始
            l_res := dbms_lob.substr(l_data, p_desired_size, p_cur_pos);
            p_cur_pos := p_cur_pos + p_desired_size;
            如果 l_res 为空 那么
                返回空值;
            万一;

            l_res := regexp_replace(l_res, C_NON_BASE64_SYM_PATTERN, '');
            p_cur_size := p_cur_size + 长度(l_res);

            l_tail_desired_size := 4 - mod(p_cur_size, 4);
            如果 l_tail_desired_size = 4 那么
                返回 l_res;
            别的
                返回 l_res || get_next_full_base64_chunk(l_data, p_cur_pos, l_tail_desired_size, p_cur_size);
            万一;
        结尾;

    开始
        dbms_lob.createtemporary(l_res, false);

        虽然是真的
        环形
            l_chunk_size := 0;
            l_chunk_buf := get_next_full_base64_chunk(p_content, l_chunk_offset, C_CHUNK_SIZE, l_chunk_size);
            当 l_chunk_buf 为空时退出;
            l_chunk_b64_buf := utl_encode.base64_decode(utl_raw.cast_to_raw(l_chunk_buf));
            dbms_lob.writeappend(l_res, utl_raw.length(l_chunk_b64_buf), l_chunk_b64_buf);
        结束循环;

        返回 l_res;
    结尾;

于 2017-12-07T18:12:06.237 回答