2013-10-23 36 views
1

我正在使用以下函數將大型base64編碼文件(圖像或語音)轉換爲blob文件並將其存儲在Oracle數據庫中(Oracle Database 11g企業版版本11.1.0.7。 0 - 生產)。將base 64解碼爲blob時出錯

我能夠存儲它並檢索它,但圖像被損壞。只有圖像的藥水正在被檢索。我試圖使用小圖像(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

+0

我的代碼的第二圖像無法上傳到SO正確。所以我拍了一張截圖並上傳,因此清晰度有所下降。 – prince

+0

也許問題不在於解碼,而是編碼?你能告訴我們你用來將圖像插入數據庫的代碼嗎? –

+0

Oracle EBS正在進行編碼。它可以完美解碼它。但是當我試圖用代碼做同樣的事情時,問題就來了。 – prince

回答

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

我8192 v_buffer_size想你的功能,它工作得很好。我已經嘗試了幾個小於32767的數字,它們都運行良好,所以嘗試一下比這更少。

+0

嗨,你是否嘗試過大尺寸的文件,比如大於100KB? – prince

+0

嗨,我嘗試使用8192 buffer_size,但生成的圖像比我在這裏發佈的內容更少。 – prince

+0

我只用你的圖像試過了,並且經歷了與32767的緩衝區大小相同的結果。對於較小的緩衝區,它完全解碼。我會嘗試一個更大的文件,並讓你知道我發現了什麼。 – furman87

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;