oracle读写文件--利用utl_file包对磁盘文件的读写操作

时间:2022-12-22 08:26:24

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; 
分类: DataBase

oracle读写文件--利用utl_file包对磁盘文件的读写操作的更多相关文章

  1. Android初级教程理论知识(第二章布局&amp&semi;读写文件)

    常见布局 相对布局 RelativeLayout 组件默认左对齐.顶部对齐 设置组件在指定组件的右边 android:layout_toRightOf="@id/tv1" 设置在指 ...

  2. SAE java应用读写文件(TmpFS和Storage)-----绝世好代码

    近期不少java用户都在提sae读写本地文件的问题,在这里结合TmpFS和Storage服务说说java应用应该如何读写文件TmpFS是一个供应用临时读写的路径,但请求过后将被销毁.出于安全考虑,sa ...

  3. Android 怎样在linux kernel 中读写文件

    前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net        ...

  4. SAE java应用读写文件(TmpFS和Storage)

    近期不少java用户都在提sae读写本地文件的问题,在这里结合TmpFS和Storage服务说说java应用应该如何读写文件TmpFS是一个供应用临时读写的路径,但请求过后将被销毁.出于安全考虑,sa ...

  5. Android测试三件套:传文件、抓包、看日志

    在对安卓进行测试时,我们需要把 apk 传到安卓机上,对请求抓包,同时监控应用日志.本文就来讲讲具体操作. 安卓机是指基于安卓的机器 ,如手机.POS 机.电视盒子等. 传文件 我们拒绝用 U 盘传文 ...

  6. Python 读写文件的正确方式

    当你用 Python 写程序时,不论是简单的脚本,还是复杂的大型项目,其中最常见的操作就是读写文件.不管是简单的文本文件.繁杂的日志文件,还是分析图片等媒体文件中的字节数据,都需要用到 Python ...

  7. oracle中utl&lowbar;file包读写文件操作实例学习

    在oracle中utl_file包提供了一些操作文本文件的函数和过程,学习了一下他的基本操作 1.创建directory,并给用户授权 复制代码 代码如下: --创建directory create ...

  8. ORACLE之UTL&lowbar;FILE包详解

    1 Utl_File包简介Oracle的UTL_FILE包用来实现对磁盘文件的I/O操作.(1)Oracle10g之前的版本需要指定utl_file包可以操作的目录.      方法:        ...

  9. Oracle之UTL&lowbar;FILE 包用法详解

    [转自] http://zhangzhongjie.iteye.com/blog/1903024 UTL_FILE包可以用来读写操作系统上的文本文件,UTL_FILE提供了在客户端(FORM等等)和服 ...

随机推荐

  1. 在Windows平台搭建PHP开发环境(四)

    一.概念 1.1 在Windows下搭建 wamp: apache(iis) + php + mysql +phpmyadmin 1.2 在Linux下搭建     lamp: linux + php ...

  2. maven &plus; selenium &plus; jenkins 教程收集

    maven + selenium + jenkins 教程收集 Complete Guide for Selenium integration with jenkins Maven http://le ...

  3. URLScan安装及配置(转)

    安装 URLScan 要安装 URLScan,请访问下面的 Microsoft Developer Network (MSDN) 网站: http://msdn2.microsoft.com/en-u ...

  4. VirtualBox 不能为虚拟电脑打开一个新的任务 可能的解决方案

    1. 在虚拟机上右键,清除保存状态 2.Cannot load R0 module C:\Program Files\Oracle\VirtualBox/VBoxDD2R0.r0: SUPR3Load ...

  5. 1&period;Tsung介绍(翻译)

    1.介绍 1.1什么是Tsung? Tsung(以前是IDX-Tsunami)是一种分布式负载测试工具.它是基于协议的,并且通常被用于压测HTTP, WebDAV, SOAP, PostgreSQL, ...

  6. Python全栈开发之路 【第一篇】:Python 介绍

    本节内容 一.Python介绍 python的创始人为荷兰人——吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆为了在阿姆斯特丹打发时间,决心开发一个新的脚本 ...

  7. 从零开始一起学习SLAM &vert; 点云平滑法线估计

    点击公众号"计算机视觉life"关注,置顶星标更快接收消息! 本文编程练习框架及数据获取方法见文末获取方式 菜单栏点击"知识星球"查看「从零开始学习SLAM」一 ...

  8. SQL Server-执行计划教会我如何创建索引

    先说点废话 以前有 DBA 在身边的时候,从来不曾考虑过数据库性能的问题,但是,当一个应用程序从头到脚都由自己完成,而且数据库面对的是接近百万的数据,看着一个页面加载速度像乌龟一样,自己心里真是有种挫 ...

  9. python自动化运维笔记3 —— dns处理模块dnspython

    1.3 DNS处理模块 dnspython是python实现的一个DNS工具包,它支持几乎所有的记录类型,可以用于查询.传输并动态更新ZONE信息,同时支持TSIG(事物签名)验证消息和EDNS0(扩 ...

  10. 人生苦短之我用Python篇(安装第三方库、正则表达式)

    安装第三方库 两种方法, 一.在DOS界面下运行 pip3 install requests 二.切换至request目录下 cd E:\ python3 setup.py install ----- ...