PLSQLでBLOBデータを扱う(Oracle) †【ファイルから登録】 set serveroutput on declare v_blob_locater blob; v_handle bfile := bfilename('LOB_DATA_PATH', 'test.jpg'); v_amount pls_integer; v_doffset pls_integer := 1; v_soffset pls_integer := 1; begin dbms_lob.fileopen(v_handle, dbms_lob.file_readonly); v_amount := dbms_lob.getlength(v_handle); insert into test_blob_data ( id, data ) values ( seq_test_blob_data.nextval, empty_blob() ) returning data into v_blob_locater; dbms_lob.loadblobfromfile( v_blob_locater, v_handle, v_amount, v_doffset, v_soffset ); dbms_output.put_line ( '書き込まれたサイズ : ' || v_doffset || 'Bytes' ); commit; dbms_lob.fileclose(v_handle); end; / 【ファイルへ読み込み】 set serveroutput on declare v_blob_locater blob; v_offset integer := 1; v_buffer long raw; v_file_buffer_size integer := 32000; v_amount integer := 32000; v_totalsize integer; v_filetype utl_file.file_type; v_filename varchar2(1000) := 'maguro_out.jpg'; v_openmode varchar(2) := 'wb'; begin select data into v_blob_locater from test_blob_data where id = 1; v_totalsize := dbms_lob.getlength(v_blob_locater); v_filetype := utl_file.fopen( 'LOB_DATA_PATH', v_filename, v_openmode, v_file_buffer_size ); while v_offset < v_totalsize loop if v_offset + v_amount > v_totalsize then v_amount := v_totalsize - v_offset + 1; end if; dbms_lob.read( v_blob_locater, v_amount, v_offset, v_buffer ); utl_file.put_raw( v_filetype, v_buffer, true ); v_offset := v_offset + v_amount; dbms_output.put_line ( 'Offset : ' || v_offset ); end loop; utl_file.fflush(v_filetype); utl_file.fclose(v_filetype); end; / 【blobからclobへ変換するFUNCTION】 /* * UTL_RAWなどを使用してBLOBをVARCHAR2に変換すると32K(VARCHAR2の最大長?)以上のデータを * 扱えない(エラーになる)為、CLOB<->BLOBの変換を行う独自関数を作成する(パクッったけど..) */ CREATE OR REPLACE FUNCTION blob2clob ( p_blob IN BLOB DEFAULT EMPTY_BLOB ( ) , p_success OUT VARCHAR2 ) RETURN CLOB IS bdoc BLOB := p_blob; cdoc CLOB := EMPTY_CLOB ( ); document CLOB := EMPTY_CLOB ( ); lob_id NUMBER; amount NUMBER; bdoc_size NUMBER; BLOCK NUMBER := 10000; blockcount NUMBER; rawbuff RAW ( 32000 ); pos NUMBER; charbuff VARCHAR2 ( 32000 ); charbuff_size NUMBER; BEGIN dbms_lob.createtemporary ( cdoc,TRUE,dbms_lob.CALL ); bdoc_size := dbms_lob.getlength ( bdoc ); IF BLOCK < bdoc_size THEN blockcount := ROUND ( ( bdoc_size / BLOCK ) + 0.5 ); ELSE blockcount := 1; END IF; pos := 1; FOR i IN 1 .. blockcount LOOP dbms_lob.READ ( bdoc,BLOCK,pos,rawbuff ); charbuff := utl_raw.cast_to_varchar2 ( rawbuff ); charbuff_size := LENGTH ( charbuff ); dbms_lob.writeappend ( cdoc,charbuff_size,charbuff ); pos := pos + BLOCK; END LOOP; p_success := 'OK'; RETURN cdoc; EXCEPTION WHEN OTHERS THEN p_success := 'ERROR::' || SQLCODE || ' -' || SQLERRM; RETURN EMPTY_CLOB ( ); END blob2clob; 【clobからblobへ変換するFUNCTION】 /* * UTL_RAWなどを使用してBLOBをVARCHAR2に変換すると32K(VARCHAR2の最大長?)以上のデータを * 扱えない(エラーになる)為、CLOB<->BLOBの変換を行う独自関数を作成する(パクッったけど..) */ create or replace function clob2blob(p_clob clob) return blob as v_blob blob; v_str varchar2(32767); v_offset integer := 1; v_length integer; v_sum integer; begin dbms_lob.createTemporary(v_blob, false, dbms_lob.SESSION); v_length := dbms_lob.getLength(p_clob); loop v_sum := 32767; dbms_lob.read(p_clob, v_sum, v_offset, v_str); dbms_lob.writeAppend(v_blob, v_sum, utl_raw.cast_to_raw(v_str)); exit when v_offset + v_sum >= v_length; v_offset := v_offset + v_sum; end loop; return v_blob; end; / |