以前曾写过PL/SQL,当时还是第一次接触,什么都不明白
顺手写了篇 《Oracle内建包UTL_FILE使用说明 》的博文,没想到还被转载(譬如百度搜索utl_file,第一篇就是,不过没写我的出处,可惜……)
http://www.blogjava.net/liwei/archive/2007/01/10/92902.html
当时项目做完就没接触PL/SQL了,时隔2年半,又要写PL/SQL了,而且遇到的问题居然还是和UTL_FILE有关。
于是上网找了些资料
http://www.shift-the-oracle.com/plsql/utl_file/utl_file_dir.html
http://www.shift-the-oracle.com/plsql/utl_file/create-directory.html
日文的,不得不说,日本人做事实在是认真,资料非常详细,看完之后,我就觉得我是高手了,可以整理点东西出来教别人了……哈哈
废话少说,开始
现在一般跑UTL_FILE.FOPEN时会出现ORA-29280的错误,出现这个错误主要有2个原因
1.文件夹没有读写权限
2.文件夹没有进行Oracle读写配置
注意:这里讨论的Oracle是在Unix类(包括linux,Solaris等)主机下安装的。
对于第1个原因,直接设定文件夹权限即可,譬如
# chmod 700 /u05/file_storage/recv_dir
这个没啥好说,不是我要说的重点。
第2个原因,可以好好说说。
Oracle进行文件夹读写配置有2种方式
1.设定UTL_FILE_DIR
2.使用DIRECTORY 对象
1.设定UTL_FILE_DIR
Oracle 8i之前,貌似没有DIRECTORY这个概念,所以只有一种方式。
编辑 initORACLE_SID.ora 文件(ORACLE_SID是个变数,因DB设定有所不同),添加
UTL_FILE_DIR='/u05/file_storage/recv_dir','/u05/file_storage/send_dir'
即可。
Oracle 9i之后还可以利用ALTER SYSTEM 命令进行设定
ALTER SYSTEM SET
UTL_FILE_DIR='/u05/file_storage/recv_dir','/u05/file_storage/send_dir'
SCOPE = SPFILE ;
也可以用命令来确认设定是否正确
SELECT NAME, VALUE FROM V$PARAMETER2 WHERE NAME='utl_file_dir' ;
注意:Oracle 8i 之后的DB不推荐使用这种方式,主要是情报泄露方面,日本很在意这个。
另外,让所有文件夹有效可使用('*')。
这种方法不方便的就是,设定了之后必须重启Oracle才能使设定有效。
使用例
CREATE OR REPLACE PROCEDURE RIVUS.UTL_FILE_DIR_WRITE_SAMPLE
AS
vHandle UTL_FILE.FILE_TYPE;
vDirname VARCHAR2(250);
vFilename VARCHAR2(250);
vOutput VARCHAR2(32767);
BEGIN
vDirname := '/u05/file_storage/send_dir'; -- 绝对路径
vFilename := 'test.txt';
vHandle := UTL_FILE.FOPEN(vDirname ,vFilename,'w', 32767);
vOutput := '利用 UTL_FILE_DIR 进行的文件处理';
UTL_FILE.PUT_LINE(vHandle, vOutput);
UTL_FILE.FCLOSE(vHandle);
EXCEPTION WHEN OTHERS THEN
UTL_FILE.FCLOSE_ALL;
RAISE;
END;
2.使用DIRECTORY 对象
从Oracle 9i 开始UTL_FILE就能使用CREATE DIRECTORY了。
首先文件夹必须存在,要有权限,我就不多说了。
然后做成DIRECTORY 对象
CREATE DIRECTORY recv_area AS '/u05/file_storage/recv_dir';
CREATE DIRECTORY send_area AS '/u05/file_storage/send_dir';
当recv_area已存在时,会出错,可使用下面这句
CREATE OR REPLACE DIRECTORY recv_area AS '/u05/file_storage/recv_dir';
接着,赋予用户该DIRECTORY 对象的读写权限
GRANT READ ON DIRECTORY recv_area TO user_name ;
GRANT WRITE ON DIRECTORY send_area TO user_name ;
同时读写权限
GRANT READ,WRITE ON DIRECTORY recv_area TO user_name ;
做好这些就可以确认了
SELECT * FROM ALL_DIRECTORIES ;
看到自己做成的DIRECTORY了吧
这里需要注意的是,当初CREATE DIRECTORY的时候是小写recv_area,现在这里是大写RECV_AREA
之后利用该DIRECTORY 对象时必须用大写。
还有,该DIRECTORY对象不包括上层目录(这个是当然的),也不包括子目录。
要利用子目录需要再定义一个子目录的DIRECTORY对象。
使用例
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;
到此为止,问题应该解决了。