oracle读写文件--利用utl_file包对磁盘文件的读写操作
oracle读写文件--利用utl_file包对磁盘文件的读写操作
摘要:
用户提出一个需求,即ORACLE中的一个表存储了照片信息,字段类型为BLOB,要求能导出成文件形式.
本想写个C#程序来做,后来想起ORACLE有很多包,功能很好很强大,于是网上参考了些文章完成了.
主要是用了ORACLE的两个包:UTL_FILE和DBMS_LOB.
实现过程:
第一步:以管理员用户登陆设置可操作目录
- --CREATE DIRECTORY privilege is granted only to SYS and SYSTEM by default.
- create or replace directory BLOBDIR as 'D:\PIC';
- grant read,write on directory BLOBDIR to sharedb;
- GRANT EXECUTE ON utl_file TO sharedb;
- select * from ALL_DIRECTORIES;
第二步:普通用户登陆,编写存储过程
- CREATE OR REPLACE PROCEDURE GET_PIC_BLOB (i_xh VARCHAR2) IS
- l_file UTL_FILE.FILE_TYPE;
- l_buffer RAW(32767);
- l_amount BINARY_INTEGER := 32767;
- l_pos INTEGER := 1;
- l_blob BLOB;
- l_blob_len INTEGER;
- BEGIN
- SELECT PIC INTO L_BLOB FROM TB_ZP WHERE PSNNO = i_xh;
- l_blob_len := DBMS_LOB.GETLENGTH(l_blob);
- l_file := UTL_FILE.FOPEN('BLOBDIR',i_xh || '.jpg','WB',32767);
- WHILE l_pos < l_blob_len LOOP
- DBMS_LOB.READ (l_blob, l_amount, l_pos, l_buffer);
- UTL_FILE.PUT_RAW(l_file, l_buffer, TRUE);
- l_pos := l_pos + l_amount;
- END LOOP;
- UTL_FILE.FCLOSE(l_file);
- EXCEPTION
- --WHEN NO_DATA_FOUND THEN
- --DBMS_OUTPUT.put_line('no data : ' || i_xh);
- WHEN OTHERS THEN
- IF UTL_FILE.IS_OPEN(l_file) THEN
- UTL_FILE.FCLOSE(l_file);
- RAISE;
- END IF;
- END GET_PIC_BLOB;
第三步:编写PL/SQL 块,循环执行该存储过程
- declare
- cursor cur_01 is
- select xh from xs_xsjbk where rownum <= 5000 ;
- begin
- for rec_01 in cur_01 loop
- GET_PIC_BLOB(rec_01.xh);
- end loop;
- end;
测试结果.取了5000条数据,其中有照片信息的为3407条.用时1分12秒,感觉还可以.
总结:
1.由管理员创建可访问目录和授权给普通用户比较重要,一开始没有注意,总是报非法路径错误,搞了较长时间在这上面.
2.存储过程中的NO_DATA_FOUND异常本来是屏显输出无照片的学号信息,但是实际运行时出错,原因是DBMS_OUTPUT.put_line打印条数过多,于是注释掉了.
3.Oracle本身提供了大量使用的包,如UTL_HTTP,DBMS_OUTPUT等,分别封装了不同的功能,进行大量的应用程序开发的可能,从而拓展了Oracle的功能.
网上参考:
- CREATE OR REPLACE PROCEDURE P_WRITE_EMP AS
- V_FILE UTL_FILE.FILE_TYPE;
- V_BUFFER VARCHAR2(32767);
- BEGIN
- V_FILE := UTL_FILE.FOPEN('D_OUTPUT', 'EMP' || TO_CHAR(SYSDATE, 'YYYY_MM_DD') || '.csv', 'w', 32767);
- V_BUFFER := 'EMPNO,ENAME,JOB,MGR,HIREDATE,SAL,COMM,DEPTNO';
- UTL_FILE.PUT_LINE(V_FILE, V_BUFFER);
- FOR I IN
- (
- SELECT '"' || EMPNO || '","' ||
- ENAME || '","' ||
- JOB || '","' ||
- MGR || '","' ||
- HIREDATE || '","' ||
- SAL || '","' ||
- COMM || '","' ||
- DEPTNO || '"' RESULT
- FROM EMP
- ) LOOP
- UTL_FILE.PUT_LINE(V_FILE, I.RESULT);
- END LOOP;
- UTL_FILE.FCLOSE(V_FILE);
- END;
- PL/SQL 3.3以上的版本中,UTL_FILE包允许用户通过PL/SQL读写操作系统文件。如下:
- declare
- file_handle UTL_FILE.FILE_TYPE;
- begin
- file_handle := UTL_FILE.FOPEN('TMP', '文件名', 'w',[1-32767]);
- --四个参数:目录,文件名,打开方式,最大行数(默认为2000)
- UTL_FILE.PUTF(file_handle, '写入的信息\n');
- UTL_FILE.FCLOSE(file_handle);
- exception
- WHEN utl_file.invalid_path THEN
- raise_application_error(-20000, 'ERROR: Invalid path for file or path not in INIT.ORA.');
- end;
- --PutF()过程用来以指定格式把文本写入一个文件
- --Put_Line()过程把一个指定的字符串写入文件并在文件中开始新的一行
- CREATE OR REPLACE PROCEDURE pReadFileTest
- (FPATH IN STRING,FNAME IN STRING,MAX_NUM IN NUMBER)
- IS
- FILE_HANDLE UTL_FILE.FILE_TYPE;
- TEXT_BUFFER STRING(1000);
- LINE_NUM NUMBER;
- BEGIN
- DBMS_OUTPUT.PUT_LINE('INPUT PATH='FPATH);
- DBMS_OUTPUT.PUT_LINE('INPUT FILENAME='FNAME);
- LINE_NUM :=0;
- BEGIN
- FILE_HANDLE := UTL_FILE.FOPEN(FPATH,FNAME,'R',MAX_NUM);
- LOOP
- LINE_NUM:= LINE_NUM + 1;
- UTL_FILE.GET_LINE(FILE_HANDLE,TEXT_BUFFER);
- DBMS_OUTPUT.PUT_LINE('LINE'LINE_NUM' : 'TEXT_BUFFER);
- END LOOP;
- EXCEPTION
- WHEN NO_DATA_FOUND THEN
- RETURN;
- WHEN UTL_FILE.INVALID_PATH THEN
- DBMS_OUTPUT.PUT_LINE('INVALID PATH');
- WHEN UTL_FILE.INVALID_MODE THEN
- DBMS_OUTPUT.PUT_LINE('INVALID MODE');
- WHEN UTL_FILE.INVALID_FILEHANDLE THEN
- DBMS_OUTPUT.PUT_LINE('INVALID FILEHANDLE');
- WHEN UTL_FILE.INVALID_OPERATION THEN
- DBMS_OUTPUT.PUT_LINE('INVALID OPERATION');
- WHEN UTL_FILE.READ_ERROR THEN
- DBMS_OUTPUT.PUT_LINE('READ ERROR');
- WHEN UTL_FILE.WRITE_ERROR THEN
- DBMS_OUTPUT.PUT_LINE('WRITE ERROR');
- WHEN UTL_FILE.INTERNAL_ERROR THEN
- DBMS_OUTPUT.PUT_LINE('INTERNAL ERROR');
- WHEN OTHERS THEN
- DBMS_OUTPUT.PUT_LINE(SQLERRM);
- END;
- EXCEPTION
- WHEN OTHERS THEN
- DBMS_OUTPUT.PUT_LINE('OTHER ERROR='SQLERRM);
- END pReadFileTest;
文件I/O对于数据库的开发来说显得很重要,比如如果数据库中的一部分数据来自于磁盘文件,那么就需要使用I/O接口把数据导入到数据库中来。在
PL/SQL中没有直接的I/O接口,一般在调试程序时可以使用Oracle自带的DBMS_OUTPUT包的put_line函数(即向屏幕进行I/O
操作)即可,但是对于磁盘文件的I/O操作它就无能为力了。其实Oracle同样也提供了可以进行文件I/O的实用包-----UTL_FILE包,利用
这个实用包提供的函数来实现对磁盘的I/O操作。
UTL_FILE包提供了很多实用的函数来进行I/O操作,主要有以下几个函数:
fopen 打开指定的目录路径的文件。
get_line 获取指定文件的一行的文本。
put_line 向指定的文件写入一行文本。
fclose 关闭指定的文件。
下面利用这些函数,实现从文件取数据,然后将数据写入到相应的数据库中。
- create or replace procedure loadfiledata(p_path varchar2,p_filename varchar2) as
- v_filehandle utl_file.file_type; --定义一个文件句柄
- v_text varchar2(100); --存放文本
- v_name test_loadfile.name%type;
- v_addr_jd test_loadfile.addr_jd%type;
- v_region test_loadfile.region%type;
- v_firstlocation number;
- v_secondlocation number;
- v_totalinserted number;
- begin
- if (p_path is null or p_filename is null) then
- goto to_end;
- end if;
- v_totalinserted:=0;
- /*open specified file*/
- v_filehandle:=utl_file.fopen(p_path,p_filename,'r');
- loop
- begin
- utl_file.get_line(v_filehandle,v_text);
- exception
- when no_data_found then
- exit;
- end ;
- v_firstlocation:=instr(v_text,',',1,1);
- v_secondlocation:=instr(v_text,',',1,2);
- v_name:=substr(v_text,1,v_firstlocation-1);
- v_addr_jd:=substr(v_text,v_firstlocation+1,v_secondlocation-v_firstlocation-1);
- v_region:=substr(v_text,v_secondlocation+1);
- /*插入数据库操作*/
- insert into test_loadfile
- values (v_name,v_addr_jd,v_region);
- commit;
- end loop;
- <<to_end>>
- null;
- end loadfiledata;
- create or replace procedure test_error
- (
- str out varchar2,
- str2 out varchar2
- )
- as
- begin
- declare
- isto_file utl_file.file_type;
- err_num number;
- i number;
- k number;
- m number;
- err_msg varchar2(100);
- fp_buffer varchar2(4000);
- begin
- isto_file := utl_file.fopen('IST0_DIR', 'kj021320.txt', 'W');
- i:=0;
- while (i<2)
- loop
- utl_file.put_line(isto_file, 'My');
- i:=i+1;
- end loop;
- utl_file.fflush(isto_file);
- utl_file.fclose(isto_file);
- isto_file := utl_file.fopen('IST0_DIR', 'kj021320.txt', 'a');
- m:=0;
- while (m<2)
- loop
- utl_file.put_line(isto_file, 'My');
- m:=m+1;
- end loop;
- utl_file.fflush(isto_file);
- utl_file.fclose(isto_file);
- isto_file := utl_file.fopen('IST0_DIR', 'kj021320.txt', 'R');
- str2:='';
- loop
- utl_file.get_line (isto_file , fp_buffer );
- str2:=str2 || fp_buffer;
- end loop;
- utl_file.fclose(isto_file);
- for j in 1..10 /* for */
- loop
- k:=11;
- end loop;
- EXCEPTION
- WHEN OTHERS THEN
- err_num:=sqlcode; /* 異常num */
- err_msg:=substr(sqlerrm,1,100); /* 異常msg */
- str:=substr(sqlerrm,1,100);
- end;
- end test_error;
- /*
- 0.为避免目录修改导致程序的修改,目录可以定义为一个常量,或ORACLE的directory。
- 1.fopen的模式: R(只读),W(读写,且首先清除原有数据),A(读写,原有数据基础上追加数据)。
- fopen的限制:
- (1)目录和文件名必须合法
- (2)目录必须存在
- (3)若为R模式,文件必须存在
- (4)若为W模式,若文件不存在,则自动创建
- (5)若为A模式,则文件必须存在
- 2.is_open:检查文件是否打开(其实只检查句柄是否为空,比如fclose_all关闭的文件,is_open仍返回true)。
- 3.get_line:读取一行数据到varchar2变量中。
- nvarchar2数据使用get_line_nchar;raw数据使用get_raw。
- 读取到文件末尾,产生no_data_found异常。还有如下三种情况也会产生no_data_found异常
- (1)无返回行的select
- (2)pl/sql集合中未定义的行
- (3)使用dbms_lob读取bfile文件至末尾。
- 所以以上四种no_data_found情况在一个pl/sql块中,要区分捕获异常
- 4.put
- 9.fclose:若关闭前缓冲区中仍有未写入文件的数据,则触发write_error异常
- .fclose_all:关闭所有打开的文件。关闭后,所有文件的句柄不变(仍为非NULL),例如测试中
- 步骤3使用fclose_all关闭文件,而is_opened仍为TRUE。但此时文件以不可读写。
- 原因:fclose传入文件句柄参数,且为IN OUT模式,调用后将句柄设置为NULL,而fclose_all
- 并未传入任何文件句柄参数,所以并未修改文件句柄的值(仍保持原值)。
- 6.frename:可以重命名文件,也可重命名路径(相当于FCOPY+FREMOVE),也可都改变
- 7.putf:put format
- 8.fgetattr:获取文件属性(是否存在,大小,块大小)
- */
- PROCEDURE prc_utl_file
- IS
- file_read_handle utl_file.file_type;
- file_write_handle utl_file.file_type;
- is_opened BOOLEAN;
- v_one_line VARCHAR2(1000);
- b_file_exist BOOLEAN;
- n_file_length NUMBER(10,2);
- bi_block_size BINARY_INTEGER;
- BEGIN
- --1.读/读写模式打开文件
- file_read_handle := utl_file.fopen('TEST_UTL_FILE_DIR_READ', 'orcl_ora_396.trc', 'R');
- file_write_handle := utl_file.fopen('TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE.txt', 'W');
- --2.检查文件是否打开
- is_opened := utl_file.is_open(file_read_handle);
- IF is_opened THEN
- dbms_output.put_line('file is opened');
- ELSE
- dbms_output.put_line('file is not opened');
- END IF;
- --3.读文件
- LOOP
- BEGIN
- utl_file.get_line(file_read_handle, v_one_line);
- dbms_output.put_line(v_one_line);
- -- 4.将读入结果写入新文件中
- utl_file.put(file_write_handle, v_one_line);
- utl_file.new_line(file_write_handle, 2);
- --utl_file.put_line(file_write_handle, v_one_line);
- --utl_file.put_line(file_write_handle, v_one_line, TRUE);
- EXCEPTION
- WHEN no_data_found THEN
- EXIT;
- WHEN OTHERS THEN
- dbms_output.put_line('error1:'||SQLERRM);
- EXIT;
- END;
- END LOOP;
- --5.关闭文件
- utl_file.fclose(file_read_handle);
- --6确认所有未决的数据都写到物理文件中
- --utl_file.fflush(file_write_handle);
- utl_file.fclose(file_write_handle);
- --utl_file.fclose_all;
- --6.检查文件是否关闭
- is_opened := utl_file.is_open(file_read_handle);
- IF is_opened THEN
- dbms_output.put_line('file is still opened');
- ELSE
- dbms_output.put_line('file is already closed');
- END IF;
- --7.拷贝文件
- utl_file.fcopy('TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE.txt', 'TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE_COPY.txt', 1, 10);
- --8.删除文件
- utl_file.fcopy('TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE.txt', 'TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE_COPY_DELETE.txt', 1, 10);
- utl_file.fremove('TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE_COPY_DELETE.txt');
- --9.重命名
- --utl_file.frename('TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE_COPY.txt', 'TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE_COPY_DELETE_RENAME.txt', FALSE);
- --10.获取重命名后的文件属性
- utl_file.fgetattr('TEST_UTL_FILE_DIR_WRITE', 'TEST_UTL_FILE_DIR_WRITE_COPY.txt',b_file_exist,n_file_length, bi_block_size);
- IF b_file_exist THEN
- dbms_output.put_line('n_file_length:'||n_file_length||'\n'||'bi_block_size'||bi_block_size);
- END IF;
- END;
oracle读写文件--利用utl_file包对磁盘文件的读写操作的更多相关文章
- Android初级教程理论知识(第二章布局&读写文件)
常见布局 相对布局 RelativeLayout 组件默认左对齐.顶部对齐 设置组件在指定组件的右边 android:layout_toRightOf="@id/tv1" 设置在指 ...
- SAE java应用读写文件(TmpFS和Storage)-----绝世好代码
近期不少java用户都在提sae读写本地文件的问题,在这里结合TmpFS和Storage服务说说java应用应该如何读写文件TmpFS是一个供应用临时读写的路径,但请求过后将被销毁.出于安全考虑,sa ...
- Android 怎样在linux kernel 中读写文件
前言 欢迎大家我分享和推荐好用的代码段~~ 声明 欢迎转载,但请保留文章原始出处: CSDN:http://www.csdn.net ...
- SAE java应用读写文件(TmpFS和Storage)
近期不少java用户都在提sae读写本地文件的问题,在这里结合TmpFS和Storage服务说说java应用应该如何读写文件TmpFS是一个供应用临时读写的路径,但请求过后将被销毁.出于安全考虑,sa ...
- Android测试三件套:传文件、抓包、看日志
在对安卓进行测试时,我们需要把 apk 传到安卓机上,对请求抓包,同时监控应用日志.本文就来讲讲具体操作. 安卓机是指基于安卓的机器 ,如手机.POS 机.电视盒子等. 传文件 我们拒绝用 U 盘传文 ...
- Python 读写文件的正确方式
当你用 Python 写程序时,不论是简单的脚本,还是复杂的大型项目,其中最常见的操作就是读写文件.不管是简单的文本文件.繁杂的日志文件,还是分析图片等媒体文件中的字节数据,都需要用到 Python ...
- oracle中utl_file包读写文件操作实例学习
在oracle中utl_file包提供了一些操作文本文件的函数和过程,学习了一下他的基本操作 1.创建directory,并给用户授权 复制代码 代码如下: --创建directory create ...
- ORACLE之UTL_FILE包详解
1 Utl_File包简介Oracle的UTL_FILE包用来实现对磁盘文件的I/O操作.(1)Oracle10g之前的版本需要指定utl_file包可以操作的目录. 方法: ...
- Oracle之UTL_FILE 包用法详解
[转自] http://zhangzhongjie.iteye.com/blog/1903024 UTL_FILE包可以用来读写操作系统上的文本文件,UTL_FILE提供了在客户端(FORM等等)和服 ...
随机推荐
- 一个人ACM(我们赶上了ACM)
时间过得真快,不经意间我已经花了两年的大学生活,现在是时候写的东西.纪念馆两年左右的时间,最近一直在玩博客.我写了一个博客.纪念我们终将逝去的青春. 就从报考说起吧.高考成绩一般,自己选择了土建类的学 ...
- C++教程之lambda表达式一
什么是Lambda? C++ 11增加了一个很重要的特性--Lambda表达式.营里(戴维营)的兄弟都对Objective-C很熟悉,很多人多block情有独钟,将各种回调函数.代理通通都用它来实现. ...
- C#动态调用WCF接口
C#动态调用WCF接口 写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项 ...
- (大数据工程师学习路径)第四步 SQL基础课程----select详解
准备 在正式开始本内容之前,需要先从github下载相关代码,搭建好一个名为mysql_shiyan的数据库(有三张表:department,employee,project),并向其中插入数据. 具 ...
- (大数据工程师学习路径)第三步 Git Community Book----中级技能(下)
一.追踪分支 1.追踪分支 在Git中‘追踪分支’是用于联系本地分支和远程分支的. 如果你在’追踪分支'(Tracking Branches)上执行推送(push)或拉取(pull)时,它会自动推送( ...
- 【ThinkingInC++】2、输入和输出流
/** *特征:输入和输出流 *时间:2014年8月8日07:37:35 *作者:cutter_point */ #include<iostream> using namespace st ...
- 问题(bug)确实不在代码逻辑上面,往往是配置、权限或者业务逻辑之外的地方(转)
不能说所有的bug都是纸老虎,但往往那种看似很奇葩的bug,导致的原因确实很简单,烦了你一段时间,找到真相又让你忍不住一笑.什么是奇葩的bug呢.我的定义是:代码逻辑都一样,但在A处是好的,到了B处就 ...
- 基于注解Spring MVC综合Hibernate(需要jar包,spring和Hibernate整合配置,springMVC组态,重定向,)批量删除
1.进口jar 2.web.xml配置 <?xml version="1.0" encoding="UTF-8"?> <web-app ver ...
- opencv2对于读书笔记——二值化——thresholded功能
opencv二进制图象值功能threshold功能 其结构 double cv::threshold( //二值化函数 const CvArr* src, //原始图像 CvArr* dst, //输 ...
- Oracle Global Finanicals Technical Reference(一个)
Skip Headers Oracle Global Finanicals Oracle Global Financials Technical Reference Manual Release 11 ...