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

转载于:https://www.cnblogs.com/edwardsun/p/3490084.html

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

  1. oracle 导出数据 utl,【原创】利用utl_file包进行表数据导出

    利用utl_file包进行表数据导出 2013/11/12 一.概述 工作中需要将许多表的数据导出到一份excel中,虽然PL/SQL自带有导出的功能,但是导出后需要进行手动的汇总到一张excel中, ...

  2. 利用UTL_FILE包实现文件I/O操作

    摘要:本文主要讨论如何利用Oracle的UTL_FILE包来实现对磁盘文件的I/O操作. 文件I/O对于数据库的开发来说显得很重要,比如如果数据库中的一部分数据来自于磁盘文件,那么就需要使用I/O接口 ...

  3. mysql utl_file_利用UTL_FILE包实现文件I/O操作

    摘要:本文主要讨论如何利用Oracle的UTL_FILE包来实现对磁盘文件的I/O操作. 文件I/O对于数据库的开发来说显得很重要,比如如果数据库中的一部分数据来自于磁盘文件,那么就需要使用I/O接口 ...

  4. python读取数据的函数详解_你了解文件缓存机制吗?磁盘文件如何读写?Python中open函数详解...

    我们知道,在使用Python打开一个文件时,一般使用的是open()函数,但是你真正了解这个函数么?文件打开后如何进行缓存?对于大文件它是如何处理的?今天,小编带你来详细了解一下-- Python如何 ...

  5. oracle utl file putf,UTL_FILE包详解(第二篇)

    3.4 PUT() 英文解释:Writes astringtoafile 用法: utl_file.put(file IN FILE_TYPE, buffer IN); 函数原型: PROCEDURE ...

  6. 【收藏】Oracle存储过程读写文件

    最近有朋友问我用Oricle存储过程读写文件,我说应该没有问题,然后本人用Google搜索一篇好文章,故收藏之! 测试环境:Oracle 9i +Linux for SUSE 有时候我们需要在文件与数 ...

  7. python打开文件写文件乱码_Python读写文件乱码问题

    对开发者来说,最恼人的问题之一莫过于读写文件的时候,由于编码千差万别,出现乱码问题.好难快速解决啊... 最近我也遇到了这样的问题,经研究,把大致的解决思路拿出来共享. 1. python中习惯首先声 ...

  8. Mysql注入读写文件

    Mysql注入读写文件 1.Mysql注入读文件 MySQL数据库在渗透测试过程中能够使用的功能还是比较多的,除了读取数据之外,还可以进行对文件进行读写(但前提是权限足够). 读取前提: 1.用户权限 ...

  9. python多进程读同一个文件_python 多进程读写文件

    import time from multiprocessing import Process, JoinableQueue, cpu_count import csv ####处理一条数据的方法 d ...

最新文章

  1. 服务器错误配置文件的xml格式,IIS配置文件的XML格式不正确
  2. python一级考试题目_全国青少年软件编程(Python)等级考试试卷(一级)br测试卷-20191114123907422...
  3. 一个用WPF做的简单计算器源代码
  4. K Balanced Teams
  5. 裸考大学英语四级写作核心词汇及模板
  6. fiddler在ios10.3系统抓包https失败原因解决
  7. SharePoint 2007 做Migration中需要注意的一些问题
  8. bt5 mysql字典,backtrack5下载
  9. matlab 给图片上画框,matlab在图片上画框
  10. Python基础--搬家具(面向对象)
  11. 大数据查询工具HBase读写设计与实践
  12. ImagePicker
  13. ip中继对接_无线路由中继以及本地固定IP设定
  14. 算法导论(三)--分治法
  15. linux中一些好玩的程序安装
  16. (转帖)互联网协会与IDGVC发布Web2.0 100
  17. 【GPLT 三阶题目集】L3-013 非常弹的球
  18. Android编程实战——仿微信群聊-2——对象的网络传输
  19. 007 GitHub上整理的一些工具
  20. 工作电子邮箱登陆方法,怎么登陆云邮箱移动办公?

热门文章

  1. 南京廖华计算机二级考试答案,全国计算机二级考试习题题库(附答案)
  2. c linux time微秒_Linux基础知识(Linux系统、Linux中的链表)
  3. go 正则表达式分组匹配_Go语言正则表达式用法实例小结【查找、匹配、替换等】...
  4. c语言教程 萌萌哒,本人C语言小白,帮我解释每段代码的意思。谢了萌萌哒
  5. micropython做产品开发_关于MicroPython是否可以真正用在产品开发的讨论
  6. python3内置函数_python3--内置函数
  7. 单片机快速将库函数版代码移植为寄存器代码方法
  8. Lambda表达式和Stream流式编程
  9. 安卓9 webview打开指定url报错或者空白
  10. MFC体系结构(3)