将base 64解码为blob时出错

时间:2013-10-23 10:39:46

标签: oracle plsql buffer blob clob

我使用以下函数将大型base64编码文件(图像或语音)转换为blob文件并将其存储在Oracle数据库中(Oracle Database 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:

附加原始图片及其解码版本,如下所示。Original picture

Decoded image

3 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

我尝试使用v_buffer_size为8192的函数,它运行正常。我尝试了几个小于32767的数字并且它们都运行良好,所以尝试一些比这更少的东西。

答案 2 :(得分:0)

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

我在网上发现了很多未正确解码的样本,在我们的代码下面发布了


    FUNCTION base64_decode(p_content CLOB) RETURN BLOB
    IS
        C_CHUNK_SIZE CONSTANT INTEGER := 12000; -- should be a multiple of 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 INTEGER := 1;
        l_chunk_size INTEGER;
        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 INTEGER;
        BEGIN
            l_res := dbms_lob.substr(l_data, p_desired_size, p_cur_pos);
            p_cur_pos := p_cur_pos + p_desired_size;
            IF l_res IS NULL THEN
                RETURN NULL;
            END IF;

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

            l_tail_desired_size := 4 - mod(p_cur_size, 4);
            IF l_tail_desired_size = 4 THEN
                RETURN l_res;
            ELSE
                RETURN l_res || get_next_full_base64_chunk(l_data, p_cur_pos, l_tail_desired_size, p_cur_size);
            END IF;
        END;

    BEGIN
        dbms_lob.createtemporary(l_res, false);

        WHILE true
        LOOP
            l_chunk_size := 0;
            l_chunk_buf := get_next_full_base64_chunk(p_content, l_chunk_offset, C_CHUNK_SIZE, l_chunk_size);
            EXIT WHEN l_chunk_buf IS NULL;
            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);
        END LOOP;

        RETURN l_res;
    END;