perl的异常处理die、warn、eval函数--DBI的RaiseError

perl的异常处理die、warn、eval函数--DBI的RaiseError,第1张

概述    在很多情况下,系统调用可能会失败;例如,尝试打开不存在的文件,或者删除某个仍含有文件的目录,或者尝试读取没有读权限的文件。在前面的示例中,我们已经用到了die函数,本节将 详细讨论有关错误处理和错误处理函数的相关内容。这些函数包括die函数、warn函数和eval函数。 die函数用于在命令或文件句柄失败时退出Perl脚本。 warn函数类似于die函数,但它不会退出脚本。 eval函数具


    在很多情况下,系统调用可能会失败;例如,尝试打开不存在的文件,或者删除某个仍含有文件的目录,或者尝试读取没有读权限的文件。在前面的示例中,我们已经用到了dIE函数,本节将 详细讨论有关错误处理和错误处理函数的相关内容。这些函数包括dIE函数、warn函数和eval函数。

dIE函数用于在命令或文件句柄失败时退出Perl脚本。

warn函数类似于dIE函数,但它不会退出脚本。

eval函数具有多种用途,但它主要还是用于异常处理。

读者想必还记得短路运算符&&和||,这两个运算符首先会求其左侧 *** 作数的值,然后才会求其右侧 *** 作数的值。如果&&左侧 *** 作数值为true,则求其右侧的 *** 作数。如果||左侧 *** 作数的值为 false,这才求其右侧的 *** 作数。

Carp.pm模块。 有很多种退出脚本的途径可供用户选择。Perl 5提供的Carp模块扩展了dIE和warn的功能。(详见示例12.10。)

18.4.1 dIE函数

如果系统调用失败的话,dIE函数会把字符串打印到STDERR上,并以$!的当前值退出脚本。$!变量中含有errno的当前值,后者是一个UNIX全局变量,含有一个表示系统错误的数字。只有在系 统调用失败时才会更新errno的值。当系统调用失败时,会向errno赋予一个数字代码,以表明错误的类型。如果在字符串中省略了换行符,则会打印出带有行号的消息(参 见/usr/include/sys中的完整列表)。

下面是/usr/include/sys/errno.h文件中的示例:

#define EPERM 1 /* Not owner */#define ENOENT 2 /* No such file or directory */#define ESRCH 3 /* No such process */#define EINTR 4 /* Interrupted system call */#define EIO 5 /* I/O error */

Win32的错误代码不同于UNIX错误代码,因此不能依赖于$!返回的值。有很多Win32扩展都提供了自己的错误函数,以便为用户提供更有意义的结果。详情可参阅ActiveState中标准Perl库里的 Win32::GetLastError相关文档。

格式

dIE(List)dIE ListdIE

示例18.66



(In Script)1 dIE "Can't cd to junk: $!\n" unless chdir "/usr/bin/junk";(Output)1 Can't cd to junk: No such file or directory


解释

1. chdir调用失败。$!中含有来自errno的错误消息。换行符导致打印了dIE函数后面的字符串,该字符串中含有变量$!的值。

示例18.67


(In Script)1 dIE unless chdir '/plop' ;(Output)1 DIEd at croak.perl line 4.


解释

1. chdir调用失败。这一次$!并不在dIE字符串中,打印发生错误的行。

示例18.68


(In Script)1 chdir '/plop' or dIE "Stopped";(Output)1 Stopped at croak.perl line 4.


解释

1. 本示例的输出内容与前一个示例相同,但它使用的不同的语法。如果chdir调用失败,就执行or右边的dIE函数。



warn函数

warn函数(运算符)和dIE几乎一样,所不同的是前者会让程序继续运行。如果在eval块中调用dIE函数,则传递给dIE的参数字符串将同样赋值给特殊变量$@。在调用dIE之后,该变量可以作为一个参数传递给warn函数,其输出将发送到STDERR上(参阅"ecal函数"一节)。


eval函数


eval函数用于处理异常,即捕捉错误。位于eval之后的语句块是作为单独的Perl程序来处理和解析的,但其所有的变量设置、子例程以及格式定义都将保持到eval执行完毕。

eval函数返回的值是上一个表达式的值。如果出现了编译或运行时错误,或者执行了dIE语句的话,则会返回未定义的值,并将特殊变量$@设置为错误消息内容。如果没有发生错误,则$@将是空字符串。

借助eval求Perl表达式的值

示例18.69

(The Script)#!/bin/perl# The eval function will evaluate each line you type# and return the result. It's as though you are# running a little independent Perl script.# Script name: plsh1 print "> "; # Print the prompt2 while(<STDIN>){3 $result=eval ; # eval evaluates the Expression $_4 warn $@ if $@; # If an error occurs,it will be assigned toprint "$result\n if $result";6 print "> "; # Print the prompt}(Output)(The Command line)$ plsh2 > hello5 hello2 > bye5 bye2 > 5 + 45 92 > 8 / 35 2.666666666666672 > 5 / 04 Illegal division by zero at (eval 5) line 3,<STDIN> line 5.> "Oh I seeCan't find string terminator '"' anywhere before EOF at (eval 6)line 1,<STDIN> line> exit

解释

1. 本行向用户打印出一个提示信息。该程序类似于小型Perl shell。它能帮助用户在把表达式放进程序之前检查它的好坏,特别是在不确定Perl会如何处理该表达式时。

2. 进入while循环。每次进入循环时,就从用户处读取一行输入,并赋值给$_。

3. 不带参数的eval将对$_中的表达式求值,并将求值结果赋予$result。

4. 如果eval发现了求值表达式引起的语法错误或系统错误的话,就将返回的错误信息赋值给变量$@。如果没有发现错误,则把$@赋值为空字符串。

5. 如果对表达式求值成功,打印其结果。

6. 显示提示信息,并再一次进入循环。

使用eval捕捉程序中的错误

示例18.70

(In Script)#!/bin/perlprint "Give me a number.";chop($a=<STDIN>);print "Give me a divisor.";chop($b=<STDIN>);1 eval{ dIE unless $answer = $a/$b ; };2 warn $@ ifprintf "division of %.2f by %.2f is %.2f.\n",$a,$b,$answer if $answer ;4 print "I'm here Now. Good-day!\n";(Output)Give me a number.45Give me a divisor.63 division of 45.00 by 6.00 is 7.50.4 I'm here Now. Good-day!(Output)Give me a number.5Give me a divisor.02 Illegal division by zero at ./eval.p line 8,<STDIN> line 2.4 I'm here Now. Good-day!

解释

1. eval函数会计算除法($a/$b),并将结果保存到$answer中。请注意,必须首先在eval中使用$answer,该会一直保留到eval执行结束。

2. 如果一切正常,并且除法运算顺利完成,则忽略这一行。如果发现错误(例如除以0),则将$@变量设置为系统错误信息,然后通过warn函数将消息打印到STDERR,并恢复程序执行。如果在eval块中调用了dIE函数,则程序不退出,而是在退出eval块之后继续执行。

3. 如果运行成功,则打印除法运算的结果。

4. 打印该行内容只是为了说明,程序即使失败了也会继续执行,因为warn函数不会导致脚本退出。

eval函数和here文档

示例18.71


(The Script)#!/bin/perl1 eval<<"EOF";2 chdir "joker" || dIE "Can't cd: $!\n";3 EOF4 print "The error message from dIE:print "Program $0 still in progress.\n";(Output)4 The error message from dIE: Can't cd: no such file or directory5 Program ./eval4.p still in progress.


解释

1. here文档类似于一种特殊形式的引用。eval函数获得位于第一个EOF和最后一个EOF之间的所有内容。

2. 如果chdir函数调用失败,则调用dIE函数,并在here文档的最后一个EOF之后恢复程序。

3. EOF表明here文档到此结束。

4. 将dIE函数的错误消息保存在变量$@中。

5. 程序继续执行。




对数据库的读取用DBI时可以设置raiseerror

my $dbh = DBI -> connect ($dsn,$user_name,$password,{raiseerror->1});

处理错误

    在dump_members 调用connect( )方法时,应该启用raiseerror 错误处理属性,以便这些错误用一条错误消息就能自动地终止相应的脚本。也可以用其他方式处理这些错误。例如,可以自己检查错误而不必使用DBI。
    为了查看如何控制DBI 的错误处理行为,我们来仔细查看一下connect( ) 调用的最终参数。下面两个相关的属性是raiseerror 和P r i n t E r r o r:
    如果启用R a i s e E r r o r(设为非零值),如果在DBI 方法中出现错误,则DBI 调用dIE( ) 来显示一条消息并且退出。
    如果启用P r i n t E r r o r,在出现DBI错误时,DBI 会调用warn( ) 来显示一条消息,但是相应脚本会继续执行。
    缺省时, raiseerror 是禁用的,而PrintError 启用。在此情况下,如果connect( )调用失败,则DBI 显示一条消息,而且继续执行。这样,如果省略connect( ) 的四个参数,则得到缺省的错误处理行为,可以如下检查错误:
    $dbh=DBI->connect($dsn,$password) or exit (1);
    如果出现错误,则connect( ) 返回undef 表示失败,并且触发对exit( ) 的调用。因为DBI 已经显示了错误消息,所以您就不一定要显示它了。
    如果明确给出该错误检查属性的缺省值,可如下调用connect( )。
    $dbh=DBI->connect($dsn,{raiseerror=>0,PrintError=>1})
    or exit (1);
    这就需要更多的编写工作,但是即使对不经意的读者,处理错误行为也会更为明显。
    如果想自己检查错误,并显示自己的消息,应该禁用raiseerror 和P r i n t E r r o r:


    变量$DBI::err 和$ DBI : :er r s t r,只用于所显示的dIE( ) 调用中,有助于构造错误消息。它们含有MysqL错误代码和错误字符串,非常像C API 函数中的MysqL_errno( ) 和MysqL_error( )。
    如果仅仅要DBI 处理错误,以便不必自己检查它们,则启用R a i s e E r r o r:
    $dbh=DBI->connect ($dsn,{raiseerror=>1});
    到目前为止,这是最容易的方法,并且是dump_members 带来的。如果在脚本退出时,想要执行某种类型的清除代码,启用raiseerror 可能是不恰当的,尽管在这种情况下,可以重新定义$SIG{_DIE_} 句柄,可以做想做的事情。
    避免启用raiseerror 属性的另一个原因是DBI 在它的消息中显示技术信息,如下:
    disconnect(DBI::db=HASH(0x197aae4)invalIDates 1active statement.Either
    destroy statement handles or call finish on them before disconnecting.
    对于编程者来说,这是好的信息,但对普通用户可能没有什么意义。在此情形,最好自己检查错误,以便可以显示对期望使用这个脚本的人更有意义的消息。或者也可在这里考虑重新定义$SIG{_DIE_} 句柄。这样可能很有用,因为它允许启用raiseerror 来使错误处理简单化,而不是用自己的消息替换DBI 给出的缺省错误消息。



下面有一个对数据 *** 作过程中做异常处理记录的代码 :

sub export_data { my ($table_name,$sql_select,$insert_columns,$columns_count,$column_types);   eval{         my $startTime=time;        ($table_name,$column_types)=@_;         my $dbh_mssql=DBI->connect("dbi:ODBC:$source_name",$source_user_name,$source_user_psd,{raiseerror =>1});		  	   $dbh_mssql->{LongTruncOk}=1;               $dbh_mssql->{LongReadLen}=1048576;          my $sth_select=$dbh_mssql->prepare($sql_select);		         $sth_select->execute() or dIE "Cannot execute: ". $sth_select->errstr();               ##生成标识ID         my $gID=rand(3200);         my $data_str="";	        my $select_data;                 while($select_data=$sth_select->fetchrow_arrayref())         {				                 if($data_str ne "")                 {                         $data_str="$data_str,";                 }                  $data_str=$data_str."[$gID,'+',['".join("','",@{$select_data})."']]";       		         }			         printf("读出时间%.1f seconds.\n",time-$startTime);$sth_select->finish;$dbh_mssql->disconnect;         $startTime=time;#open(file,">>all_export_data_fre.txt");    #syswrite(file,"$data_str\n");    #close(file);     $data_str=encode("utf8",decode("gbk",$data_str));#open(file,">>all_export_data.txt");    #syswrite(file,"$data_str\n");    #close(file);            ##测试的时候,查看数据的语句。     # print "\n",$data_str,"\n";          if($data_str ne "")         {             $data_str="[$data_str]";             my $args = { host => $aim_ip,port => $hs_port };             my $hs = new Net::HandlerSocket($args);             my $res = $hs->open_index($gID,$aim_db_name,$table_name,'PRIMARY',"$insert_columns");             dIE $hs->get_error()  if $res != 0;					               ##这里不加EVAL不行的,不信?您试			 $res = $hs->execute_multi(eval($data_str));                       dIE $hs->get_error() if $hs->get_error() != 0;             $hs->close();         }        undef $data_str;         printf("写入时间%.1f seconds.\n",time-$startTime);		 };				  print "An error occurred: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"  if  $@;if($@){ open(file,">>$logname");  syswrite(file,"$n\n"); 	 syswrite(file,"$table_name\n");    syswrite(file,"$sql_select\n");  syswrite(file,"$@\n"); ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time());  $format_time=sprintf("%d-%d-%d %d:%d:%d",$year+1990,$mon+1,$sec); syswrite(file,$format_time."\n");    close(file);  open(file,">>$repairname");  syswrite(file,"$table_name\:\:$sql_select\:\:");    close(file); }print "An error occurred: $@"  if  $@;}
总结

以上是内存溢出为你收集整理的perl的异常处理die、warn、eval函数--DBI的RaiseError全部内容,希望文章能够帮你解决perl的异常处理die、warn、eval函数--DBI的RaiseError所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1279201.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-09
下一篇 2022-06-09

发表评论

登录后才能评论

评论列表(0条)

保存