UTL_FILE パッケージの使い方 (CREATE DIRECTORY 編) Oracle 9i

UTL_FILE パッケージによって PL/SQL でファイルの入出力を行うことができる。Oracle 9i 以降では CREATE DIRECTORY を使用すると ユーザ単位、読み込み、書き込みの制限が可能になる。 また、ディレクトリを追加したい場合にも Oracle の再起動が不要になるためダウンタイムを少なくすることができる。

UTL_FILE 準備作業

ディレクトリファイルの作成 (UTL_FILE_DIR 編と同じ)

ディレクトリを作成するときに OS の DBA であるユーザー(通常は oracle)でディレクトリを作成する。

内容は省略 ⇒ UTL_FILE の使い方 (UTL_FILE_DIR 編)の準備作業を参照

ディレクトリ・オブジェクトによるファイルアクセス Oracle 9i

ディレクトリの作成 CREATE DIRECTORY

Oracle 9i から UTL_FILE パッケージが CREATE DIRECTORY に対応するようになった。
ディレクトリの追加にともなう再起動も不要。

  • ディレクトリオブジェクトの作成
    DIRECTORY の作成には、CREATE DIRECTORY 権限 が必要。
    CREATE DIRECTORY recv_area AS '/u05/file_storage/recv_dir';
    CREATE DIRECTORY send_area AS '/u05/file_storage/send_dir';
  • ディレクトリへのアクセス権の設定
    読み込み権限と書き込み権限は個別に行なう。
    GRANT READ ON DIRECTORY recv_area TO user_name ;
    GRANT WRITE ON DIRECTORY send_area TO user_name ;
    -- 確認
    SELECT * FROM ALL_DIRECTORIES ;

アクセスできるのは 対象のディレクトリのみで上層はもちろんであるが、下層のディレクトリにもアクセスできない。
下層のディレクトリにアクセスすると実行時に ORA-29280 エラー が発生する。
ディレクトリオブジェクト定義のスナップショットでもよいから下層ディレクトリを含む強力?な DIRECTORY オブジェクトが出てくるか、ディレクトリグループのような概念が登場することをひそかに期待している。

FOPEN 〜 PUT_LINE ファイル書き込み(ディレクトリ・オブジェクト使用時)

CREATE OR REPLACE PROCEDURE RIVUS.CREATE_DIR_WRITE_SAMPLE
AS
	vHandle		UTL_FILE.FILE_TYPE;
	vDirname	VARCHAR2(250);
	vFilename	VARCHAR2(250);
	vOutput		VARCHAR2(32767);
BEGIN
	vDirname := 'SEND_AREA';   -- (注) ディレクトリオブジェクト名を大文字で指定する
	vFilename := 'test.txt';
	vHandle := UTL_FILE.FOPEN(vDirname ,vFilename,'w', 32767);
 
	vOutput := 'CREATE DIRECTORY 経由でのファイル出力です';
	UTL_FILE.PUT_LINE(vHandle, vOutput);
	UTL_FILE.FCLOSE(vHandle);
EXCEPTION WHEN OTHERS THEN
	UTL_FILE.FCLOSE_ALL;
	RAISE;
END;
/

(注) ディレクトリオブジェクト名を大文字で指定しなければエラーとなる。

GET_LINE ファイル読み込み ( ディレクトリ・オブジェクト使用時 )

ファイル書き込みで作成したファイルを読込先のディレクトリにコピーして実行。

CREATE OR REPLACE PROCEDURE RIVUS.CREATE_DIR_READ_SAMPLE
AS
	vHandle		UTL_FILE.FILE_TYPE;
	vDirname	VARCHAR2(250);
	vFilename	VARCHAR2(250);
	vInput		VARCHAR2(32767);
BEGIN
	vDirname := 'RECV_AREA';
	vFilename := 'test.txt';
	vHandle := UTL_FILE.FOPEN(vDirname ,vFilename,'r', 32767);
 
	BEGIN
		LOOP
			UTL_FILE.GET_LINE(vHandle, vInput,32767);
			DBMS_OUTPUT.PUT_LINE(vInput);
		END LOOP;
	EXCEPTION
	WHEN NO_DATA_FOUND THEN
		DBMS_OUTPUT.PUT_LINE('ファイルの終わりを検出しました');
	END;
	UTL_FILE.FCLOSE(vHandle);
EXCEPTION WHEN OTHERS THEN
	UTL_FILE.FCLOSE_ALL;
	RAISE;
END;
/

注意事項

  • UTL_FILE パッケージで使用できる、一度に入出力できる長さは 32767(32K) バイト (※)
  • OPEN したファイルは必ず CLOSE するように例外処理を施しておく。UTL_FILE.FCLOSE_ALL を使うと便利
  • Oracle 11g からシンボリックリンクのファイルは利用できない。
  • RAW 型を出力することはできるが行末には OS 固有の改行コードが必ず付与される。Oracle 9i
    Oracle 10g では wb による (RAW モード) FOPEN がサポートされているので、そちらを使うと問題ない。 Oracle 10g

この制限により Oracle 10g 以降でなければ純粋なバイナリファイルを扱うことができない。

(※) 一度の書き込みで 32KB を超えることはできないが、RAW モードでの書き込みにおいては 複数回に書き込みを分割することで1行が 32KB を超過することが可能である。

テキストモードで正しく扱えているように見えるサンプルも Web 上にあるが、厳密には内容が意図しないバイト列に書き換わっているため使用を避けた方がよいと思う。

例えば BLOB の内容を UTL_FILE.PUT_RAW を用いてファイル出力しても特定の用途(※1)と偶然性による特異なデータ配列(※2)にならない限り、そのファイルの一部が壊れてしまって価値がなくなるか、出力プログラムはエラーになる。

(※1) 一部のメディアファイルのフォーマットはファイルの一部にゴミデータが付与されていても再生・表示できる。

(※2) データのバイト列が 32K バイト連続して 0x0A(LF:改行)を含まない場合にはファイル書き込みエラーになる。

もし 32 KB 以内の RAW だけを出力する場合でもあっても最後のバッファをフラッシュ(※3) または、クローズすると OS 固有の改行コードが必ず付与されるため結局はバイナリデータとして扱うことができていない。

(※3) テキストモードでは UTL_FILE.FFLUSH を使用してもバッファに改行が含まれない場合には書き出されない仕様になっている。また含まれていている場合でも改行コード以前までの内容がフラッシュされる。CLOSE 時には最後に改行が自動的に付与される。



ファイル I/O 関連事項

日本オラクル
■ 日本オラクル 株式会社
■ オラクルマスター資格 (オラクルマスターとは
■ オラクルサポートセンター