[Oracle] LOBデータをファイルに直接出力する方法 | Archive Redo Blog

Archive Redo Blog

DBエンジニアのあれこれ備忘録

LOBデータをファイルから直接登録するには、"LOBデータをファイルから直接登録する方法(その1) "、"LOBデータをファイルから直接登録する方法(その2) "で説明したとおり、DBMS_LOBパッケージのLOADFROMFILEかまたはJavaストアドプロシージャを利用すればOKです。

では、逆にLOBデータをファイルに直接出力するにはどうすればいいのでしょうか?

DBMS_LOBパッケージにはLOBデータをファイルに直接出力するプロシージャはなぜか用意されていません。

そこでDBMS_LOBパッケージに代わる方法としてJavaストアドプロシージャを利用する方法のみを説明します。

※ここではBLOBデータを例に説明します。

JavaストアドプロシージャでLOBデータをファイルに直接出力する場合、まず、BLOBデータを読み込んでファイルに出力するメソッドを持つJavaのクラスを用意します。

package orcl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStream;
import oracle.sql.BLOB;

public class UtlLob {

  public static long downLoadBlob( BLOB blob, String dirName, String fileName ) {
    
    File dir = null;
    File file = null;
    FileOutputStream fos = null;
    InputStream ins = null;

    try {

      //ディレクトリのFileオブジェクトを生成します。
      dir = new File( dirName );

      //ディレクトリが存在しない場合、終了します。(失敗)
      if( !dir.exists() ) {
        return -1L;
      }

      //出力ファイルのFileオブジェクトを生成します。
      file = new File( dir, fileName );
      //出力ファイルへの出力ストリームを生成します。
      fos = new FileOutputStream( file );
      //BLOBファイルの入力ストリームを生成します。
      ins = blob.getBinaryStream();
      //BLOBデータの読み込みに最適なバッファ・サイズを算出し、バッファを生成します。
         byte[] buffer = new byte[ blob.getChunkSize() ];
      //BLOBデータが空の場合、終了します。
      if( ins == null ){
        return 0;
      }
      else {
        //バッファ・サイズ単位でBLOBデータを読み込み、出力ファイルに書き込みます。
           int length = -1;
           while( ( length = ins.read( buffer ) ) != -1 ) {
              fos.write( buffer , 0 , length );
        }
      }
      return blob.length();

    } catch (Exception e) {
      e.printStackTrace();
      return -1L;
      } finally {
      try { ins.close(); } catch( Exception ignore ) {}
      try { fos.close(); } catch( Exception ignore ) {}
    }
  }

}

このJavaクラスでは、BLOBロケータ、ディレクトリ名、ファイル名を引数として受け取り、指定されたBLOBロケータからBLOBデータを読み込んで指定されたファイルに流し込んでいます。

そして、このJavaクラスをCREATE JAVA文を使ってOracleにロードし、以下のような呼び出しの仕様(コール・スペック)を定義します。

CREATE OR REPLACE FUNCTION UTLLOB_DOWNLOADBLOB_FUNC ( 
  p_blob BLOB, p_dir VARCHAR2, p_file VARCHAR2 
) RETURN NUMBER
AS LANGUAGE JAVA
  NAME 'orcl.UtlLob.downLoadBlob( oracle.sql.BLOB, java.lang.String, java.lang.String ) return long';
/

そして、このJavaクラスがファイルにアクセスできるようJAVAのセキュリティを設定する。

CALL dbms_java.grant_permission( 
  'SCOTT', 'SYS:java.io.FilePermission', '<>', 'read' 
)
/

CALL dbms_java.grant_permission( 
  'SCOTT', 'SYS:java.io.FilePermission', '<>', 'write' 
)
/

CALL dbms_java.grant_permission( 
  'SCOTT', 'SYS:java.lang.RuntimePermission', 'writeFileDescriptor', '' 
)
/

CALL dbms_java.grant_permission( 
  'SCOTT', 'SYS:java.lang.RuntimePermission', 'readFileDescriptor', '' 
)
/

以上でようやくファイルにアクセスするJavaストアロプロシージャが準備ができたことになります。

このJavaストアドプロシージャを利用して、BLOBデータをファイルに直接出力するには以下のような手順をとります。

DECLARE
  wk_blob        BLOB;          --BLOBロケータ
  wk_length      NUMBER(38);        --BFILEロケータ

BEGIN
  --BLOBロケータ取得
  SELECT COL3 INTO wk_blob
    FROM TABLEA
    WHERE COL1 = 1;
  --ファイルをBLOBロケータにロード
  wk_length := UTLLOB_DOWNLOADBLOB_FUNC( wk_blob, 'C:\\Temp', 'TEST.DAT' );
END;
/

ご覧の通り、Javaストアドプロシージャさえ準備できれば、あとはSELECT文で出力するBLOBデータのBLOBロケータを取得し、Javaストアドプロシージャを呼び出すだけ。

非常に簡単です。



【関連エントリ】
[Oracle] LOBデータの基本的な扱い方 2004/12/03
[Oracle] JDBCによるLOBの操作方法 2004/12/06
[Oracle] LOBデータをファイルから直接登録する方法(その1) 2005/01/25
[Oracle] LOBデータをファイルから直接登録する方法(その2) 2005/01/27
[Oracle] LOBデータをファイルに直接出力する方法 2005/02/01
[Oracle] JavaでLOBデータを読み込む際の最適なバッファサイズは? 2005/02/02
[Oracle] LOB記憶特性 その1(STORAGE IN ROW) 2005/08/23
[Oracle] LOB記憶特性 その2(CHUNK) 2005/08/24