Oracle9i第2版中的UNT_FILE提高了文件输入/输出(I/O)功能。

技术 PL/SQL

提高文件操作功能

作者:Steven Feuerstein

Oracle9i第2版中的UNT_FILE提高了文件输入/输出(I/O)功能。

有些人可能会说你可以在Oracle数据库中包含和表示整个世界,甚至是整个宇宙。这或许是真的,但我们中仍有一些人希望能够从我们的PL/SQL程序内部处理操作系统(OS)文件。有了这个愿望,开发人员在很长时间内就同UTL_FILE包之间有了一种爱憎交加的关系。

相关链接 Oracle技术网站(OTN)上关于UTL_FILE的示例 otn.oracle.com/oramag/utl_file.html

几年来,UTL_FILE提供了一种在PL/SQL中读写文件的途径。但是,开发团体中的一些人希望能有进一步的发展,而不是仅停留在在文件中依次读写行的层次上。有些开发人员希望能够对文件进行删除、重命名以及执行其他与文件相关的典型操作,但是UTL_FILE并不支持这些操作。

Oracle9i第2版对这些讨厌的UTL_FILE限制进行了改进。本文探讨了Oracle9i第2版在UTL_FILE包中增加的一些非常有用的新功能,包括:

  • UTL_FILE.FREMOVE 删除文件。
  • UTL_FILE.FRENAME 重命名文件,事实上,还可以移动文件。
  • UTL_FILE.FCOPY 将一个文件的全部或部分复制到另一个文件中。
  • UTL_FILE.FGETATTR获取文件的长度之类的属性。

除了新程序之外,UTL_FILE现在还允许数据库定义的目录对象指定操作系统目录的位置。尽管本文不可能包括UTL_FILE的所有新特性,但它介绍的内容仍然足以使你对在本地PL/SQL代码中进行文件I/O操作的新特性感到兴奋。

对目录进行操作

在Oracle9i第2版之前,当调用FOPEN打开文件(用于读或写)时,UTL_FILE要求必须明确指出文件的位置。这不是最优的实施,因为它意味着开发人员必须在应用程序中的多个地方对那些位置进行硬编码(hard-code)。如果目录改变了,就必须进行很多麻烦的整理工作。

你现在可以在Oracle9i第2版中为目录的文件系统位置指定一个Oracle目录对象的名字。这种技巧"隐藏"了实际的操作系统位置。如果那个位置需要改变,只需要更新目录对象的定义,所有对FOPEN,FREMOVE,FRENAME和FCOPY的调用都不会受到影响。

为了创建一个目录对象,需要具备CREATE ANY DIRECTORY权限,然后就可以像下面的例子那样定义一个新的目录对象:

CREATE OR REPLACE DIRECTORY DEVELOPMENT_
   DIR as '/dev/source';
CREATE OR REPLACE DIRECTORY TEST_DIR 
   as '/test/source';

你应当知道当你创建目录对象时,Oracle数据库并不会验证你所指定的位置。另一点需要留意的是当你在一个调用(如调用UTL_FILE.FOPEN)中指定目录对象的名字时,它被看作一个区分大小写的字符串。换而言之,如果你不是用大写字母指定目录对象的名字,操作将会失败。

在创建了目录对象之后,你可以按下面的方法授权特定的用户使用目录对象:

GRANT READ ON DIRECTORY DEVELOPMENT_DIR 
   to senior_developer;

最后,你可以查询ALL_DIRECTORIES的内容来确定在当前连接的模式中,哪些目录对象可用。这里有一个布尔函数会告诉你指定的目录对象是否可用:

CREATE OR REPLACE FUNCTION dir_available (
   dir_in       IN   VARCHAR2,   
   uppercase_in  IN   BOOLEAN := TRUE
)
   RETURN BOOLEAN
IS 
   v_dir    VARCHAR2 (100) := dir_in;
   retval   BOOLEAN;
   dummy    CHAR (1);
BEGIN
   IF uppercase_in
   THEN

      v_dir := UPPER (v_dir);
   END IF;
   SELECT 'x'
     INTO dummy
     FROM all_directories
    WHERE directory_name = l_dir;
   RETURN TRUE;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      RETURN FALSE;
END;

采用这种方法创建实用程序的一个好处是:你可以很轻松地增加关于目录大小写的高级操作,以避免格式错误,如忘记指定目录名字为大写等。

复制、删除和移动文件

在过去,利用UTL_FILE复制文件唯一的方法是编写大量代码来逐行读取一个文件的内容,然后再将其逐行写到一个新的文件。现在,你只需要让UTL_FILE来为你完成这项工作。在清单1中,我用UTL_FILE.FCOPY执行一个选择性的备份--一个从开发目录到存档目录的单一文件的复制。

你也可以用FCOPY仅复制一个文件的一部分。为此,你需要指明文件中希望复制的起始和结束行号。假设我有一个文本文件,其中包含有我儿子的保龄球联盟锦标赛各年冠军的名字。我从1990年开始记录这些名字,并希望将1996年之前的所有名字移到另一个文件。我可以利用下面程序的第5个和第6个参数来完成这个操作:

- Copy just a part of a file
UTL_FILE.fcopy (
   src_location      => 'WINNERS_DIR',

   src_filename      => 'names.txt',
   dest_location     => 'OLD_NEWS_DIR',
   dest_filename     => 'prevnames.txt',
   start_line        => 1,
   end_line          => 6
   );

删除文件也是一件非常容易的事情。假设在将我的zip文件移到存档目录之后,为了释放一些磁盘空间,我希望将它删除。这是部署UTL_FILE.FREMOVE的好机会。注意,在清单2中,我还为新的UTL_FILE.DELETE_FAILED异常定义了一个明确的异常句柄。这种方法使我能对失败的删除操作进行标记(例如,因为我没有所需的权限而导致的失败。)

我还可以通过调用UTL_FILE.FRENAME程序将复制和删除操作合并为一步。这个方便的实用程序使我既能够在相同的目录中重命名文件,也能够对文件的位置和名字都进行重新命名(实际上就是移动文件)。清单3中的例子使用了FRENAME来移动文件archive.zip。

再次说明,当你使用FRENAME时,你应该定义一个异常句柄,它可以十分清楚地捕获重命名失败。

获得一个文件的属性

这个文件有多大?某个特定的文件是否存在?我的文件的块大小是多少?有了操作系统命令的帮助,这些问题不再神秘。UTL_FILE. FGETATTR现在可以在一个本地程序调用中提供所有这些信息。也许利用FGETATTER的最好方法是建立你自己的函数--在内置函数上--来回答一个问题,如清单4中返回一个文件大小(长度)的例子。

有了适当的函数,我现在可以很容易地得到文件的大小,而不必为每个通过FGETATTER得到的属性声明一个变量,如下面的PL/SQL例子:

how_big := flength ('DEVELOPMENT_DIR',
   'all_the_rules.pkg');

这个FLENGTH函数还包括查找一个文件块大小和确定一个文件是否存在的代码。你可以很容易地使用与查找文件长度(大小)相同的技巧(如清单4所示)创建函数,以得到块的大小,并返回一个简单的布尔值来确定文件是否存在。

在写文件时提高了控制能力

UTL_FILE的另一个新功能是PUT_LINE的“自动清洗(auto-flush)”特性。当你在程序中将数据写出到一个文件中时,它不会立即显示在那个文件中,以备读取。操作系统肯定会利用异步I/O,将多个写操作的结果输出到缓冲区,然后再将它们发送到磁盘上。

尽管异步I/O提高了性能,但对于那些需要立即看到一个文件(如日志文件)内容的程序员或支持人员来说,这是一个非常不方便的特性。

现在,UTL_FILE在UTL_FILE.PUT_LINE程序中包括了一个新的参数,以便开发人员可以指定她希望立即输出到磁盘的文本行。清单5中的程序说明了这一技巧。

Oracle对开发人员要求的响应

为使PL/SQL应用更为广泛,更为成功,它必须强有力地支持大量功能。与操作系统文件的交互当然是其中的一个关键部分。

Oracle又一次响应了开发团体的要求,并改进了PL/SQL的核心功能。Oracle9i第2版中的UTL_FILE现在对常用操作的支持已经达到了相当高的水平。

Steven Feuerstein (stevenfeuerstein@quest.com) 从1980年开始开发软件,他是PL/SQL语言的权威。Steven编写了六本关于PL/SQL的书,其中包括《PL/SQL最佳实践》(PL/SQL Best Practices)和《Oracle PL/SQL编程》(Oracle PL/SQL Programming)(都由 O'Reilly & Associates出版)。他是Quest Software公司的高级技术顾问。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏NetCore

[实录]解决Migrator.Net 小bug

好久没写了,平时比较忙,只能趁周末的时候,写一点小东西,自己也记录一下。 平时我们做项目的时候,都会有自己的数据访问层,为了能方便以后的升级,我们一般会抽象出数...

25350
来自专栏程序员的SOD蜜

EF+MySQL乐观锁控制电商并发下单扣减库存,在高并发下的问题

下订单减库存的方式 现在,连农村的大姐都会用手机上淘宝购物了,相信电商对大家已经非常熟悉了,如果熟悉电商开发的同学,就知道在买家下单购买商品的时候,是需要扣减库...

80180
来自专栏互联网大杂烩

数据库

◆ 第一范式(1NF):强调的是列的原子性,即列不能够再分成其他几列。 ◆ 第二范式(2NF):首先是 1NF,另外包含两部分内容,一是表必须有一个主键;二是...

7020
来自专栏散尽浮华

mysql操作命令梳理(5)-执行sql语句查询即mysql状态说明

在日常mysql运维中,经常要查询当前mysql下正在执行的sql语句及其他在跑的mysql相关线程,这就用到mysql processlist这个命令了。 m...

27160
来自专栏晨星先生的自留地

面试中遇到的坑之mysql注入入门

26940
来自专栏c#开发者

分析Oracle数据库日志文件(1)

分析Oracle数据库日志文件(1) 一、如何分析即LogMiner解释 从目前来看,分析Oracle日志的唯一方法就是使用Oracle公司提供的LogMin...

48850
来自专栏大内老A

在Entity Framework中使用存储过程(一):实现存储过程的自动映射

之前给自己放了一个比较长的假期,在这期间基本上没怎么来园子逛。很多朋友的留言也没有一一回复,在这里先向大家道个歉。最近一段时间的工作任务是如何将ADO.NET ...

37450
来自专栏魏艾斯博客www.vpsss.net

MySQL 数据库类型从 InnoDB 转换为 MyISAM

魏艾斯博客有一个 wordpress 站点,有一天无意中发现数据库挺大的,可是这个站也就不到 10 篇文章,没道理这么大的数据库啊。然后开始查找原因,发现在 p...

533220
来自专栏魏艾斯博客www.vpsss.net

MySQL 数据库类型从 InnoDB 转换为 MyISAM

19160
来自专栏xiaoheike

Neo4j 查询已经创建的索引与约束

在Neo4j 2.0之后为cypher语法增加了一些类似于DDL的语法,能够自己创建索引,约束等等。

45920

扫码关注云+社区

领取腾讯云代金券