我使用以下函数将大型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:
附加原始图片及其解码版本,如下所示。
答案 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;