Perl输入与输出 (二)

版权声明:转载请说明出处! https://blog.csdn.net/qq_39556143/article/details/84900049

Perl输入与输出(2)

2 文件句柄

文件句柄(filehandle)其实是perl程序里面代表Perl进程和外界I/O进行通信的接口,也就是说,文件句柄其实是这种接口的名字,而不是文件的名字,通过这种机制,Perl几乎可以喝任何一个外部实体交换信息。

  • 句柄命名
    • 句柄的名称和其他Perl标志符一样,必须由字母,数字和下划线组成,但是不能以数字开头;
    • 为了避免和其他字符混淆,建议句柄用全部大写字母来命名。
  • Perl的6个特殊句柄
    • STDIN :标准数据输入 (默认为键盘输入)
    • STDOUT:标准数据输出(默认为终端屏幕)
    • STDERR:标准错误输出 (默认为终端屏幕,先于STDOUT输出)
    • DATA:
    • ARGV:
    • ARGVOUT:
#!/usr/bin/perl
./script.pl  <dino >wilma
#程序从标准输入接受数据,输出到标准输出
#shell负责将标准输入连接至文件dino读取数据,将标准输出送至文件wilma
cat fred barney | sort | ./script.pl | grep somthing | lpr
#1 cat    读取fred barney文件的每一行并输出
#2 sort   将cat的输出作为输入,进行每一行的排序
#3 script 将sort的排序后的输出作为输入,进行处理并输出
#4 grep   将script的输出结果进行搜索,并输出
#5 lpr    将grep输出的数据,作为输入总之打印机
#以上是Unix的管道操作符的用法

2.1 打开文件句柄

以上的三种默认文件句柄STDIN,STDOUT 和 STDERR 是由Perl的父进程 shell 默认打开的,当我们需要使用其他文件句柄时,可以使用 open 操作符打开文件句柄。

#!/usr/bin/perl
open CONFIG,'dino' ;    #通过句柄CONFIG从dino读取数据(默认是读取操作)
open CONFIG,'<dino';    #通过句柄CONFIG从dino读取数据,'<'表示读取操作
open BEDROCK,'>fred';   #通过句柄CONFIG向fred写入数据,'>'表示输出操作,如果文件fred已经存在,清除原来内容然后写入新内容
oren LOG,'>>logfile';   #通过句柄LOG向logfile写入数据,'>>'表示追加操作,如果文件logfile已经存在,新的内容将添加在原内容后方;如果不存在创建新文件。
#warning
my $file_name = '>my_file';
open LOG,'> $file_name';  
#>后空格的空格可以防止意外发生:
#(1) >>$file_name(追加方式写入文件'file_name');
#(2) > >file_name(写入方式写入文件'>myfile')

#三个参数形式的open操作
open CONFIG,'<','dino';       
open BEDROCK,'>',$file_name;
open LOG,'>>',&logfile_name;
#通过三参数写法可以指定数据编码格式
open CONFIG,'<:utf8','dino';      
  • 以二进制方式读写文件句柄
    • 通过文件句柄处理数据时,我们可以不用关心原始数据的编码方式,直接以二进制数据流的方式读写,句柄前加上binmode即可。这样即使二进制文件内部碰巧出现内部编码和换行符相同的字符,也不会将其当做文本文件的换行符处理。
#!/usr/bin/perl
binmode STDOUT;  #不会转换换行符
binmode STDERR;  #不会转换换行符
  • 异常文件句柄的处理
    • 当perl通过shell打开操作系统中的文件时,不能自己处理,只能通过操作系统代为处理,如果没有相应的读写权限,操作系统会拒绝打开。
    • 如果打开文件失败,会立即读取到文件结尾;
    • 如果大尅文件失败,写入的数据将会被无声丢弃;
    • 使用“-w”选项可以自动发出打开文件失败警告 (我们也可以用die函数处理)
  • die函数处理致命错误
    • 如果文件打开失败,或者程序出现致命错误,比如除以零的操作,这时候我们希望立即结束程序,并发出错误信息。
    • die函数的参数,是要输出的文本信息,默认输出到标准错误输出STDERR,同时结束程序,在shell中返回不为零的退出码。
    • warn函数和die函数的区别:warn函数只报告错误信息,不会中止程序运行。
    • 使用autodie自动检测致命错误;
#!/usr/bin/perl
if (! open LOG,'>>','logfile') {
	die "Cannot open logfile: $!";
}
#如果open失败,die会终止程序的运行,并输出:Cannot open logfile: n
#其中n表示,失败类型,也许是权限不足,也许是文件找不到之类的信息。
#Result Example
  Cannot open logfile: 2 permission denied at script.pl line 1234
#die函数会默认之处程序文件名报错行号,方便程序员DEBUG

#warn 函数
if (! open LOG,'>>','logfile') {
	warn "Cannot open logfile: $!";
}
#warn可以发出类似的警告信息,但是程序执行到warn函数不会直接退出,其他的和die相同。

#autodie
use autodie;
open LOG,'>>','logfile';  #和以上die程序相同
  • 关闭文件句柄
    • 使用close可以关闭文件句柄,close BEDROCK;表示向BEDROCK的输出已经书写完毕。
    • 使用open打开文件句柄时,前一个的文件句柄自动关闭;
    • 程序结束时,perl会默认关闭所有句柄;

2.2 使用文件句柄

文件句柄打开后,就可以像从STDIN读取标准输入流一样,一行一行的读取他的数据。

#!/usr/bin/perl
#选择输入文件源
if (!open PASSWD,'<','/etc/passwd'){
	die "Cannot open passwd: $!";
}
while (<PASSWD>) {   #使用尖括号< >和文件句柄就可以读取对应文件中的数据
	chomp;
	...
}
#选择输出文件源,注意:句柄和字符串之间是空格 不是逗号!
print LOG "This is a test file.\n";
printf STDERR "%0d percent complete.\n", $done/$total*100;
  • 改变默认输出句柄
    • print 函数和 printf 函数的默认输出都是STDOUT,当我们想每次输出到文件LOG时,都用以上的方式显得十分麻烦。
    • 使用 select 操作符可以改变默认输出的文件句柄。如select LOG;
    • 一旦选择了输出默认句柄,后面所有的输出都会送到 select 选择的文件,如果想选回标准输出使用select STDOUT。
#!/usr/bin/perl
select LOG;
print "I hope send data to file logfile.";
printf "%0d percent complete.\n", $done/$total*100;
$| = 1;  #不要将LOG的内容保存在缓存区
#转回标准输出
select STDOUT;
print "Send data to STDOUT";
  • 默认情况下,输出会先存放在缓存区,当数量达到一定程度后在统一送至指定文件;
  • 如果希望实时发送,将特殊变量$| 设置为1 即可。(但是这样会降低程序运行速度,不建议)
  • 重新打开标准文件句柄
#!/usr/bin/perl
if (! open STDERR '>>','/etc/barney') {
	die "Cannot open /etc/barney";
}
  • 重用系统标准错误输出,这时如果打开文件失败,我们能否看到错误信息?
  • 当然可以,当我们重用系统默认文件句柄时,如果重用失败,perl会贴心的帮我们把原来的文件句柄打开。
  • 三要点理解:
  1. 重新打开某个句柄时,原来已经打开的同名句柄,会被perl自动关闭;
  2. 尽量不要重用系统的六个默认句柄;
  3. die函数和warn函数的输出信息,默认输出至STDOUT(用户终端屏幕)。

2.3 标量变量中的文件句柄

  • 从perl 5.6开始,我们可以把文件句柄存放在标量变量中,而不必非得使用裸字;
  • 当文件句柄存放在标量变量中以后,就可以在数组,哈希中排序,也可以通过子程序传递;
  • 除非特殊需要,尽量用裸字存储文件句柄,没有必要用标量变量存储文件句柄。
    • 在 open 函数中原来使用裸字的地方写上不含任何值得变量,那么文件句柄就会存放在那个变量中。
#!/usr/bin/perl
my $rock_fh;
open $rock_fh, '<','rock.txt' 
 or die "Could not open rock.txt";
#也可以合并成一句
open my $rock_fh, '<','rock.txt' 
 or die "Could not open rock.txt";
#以后就可以使用这个标量变量代替文件句柄,调用文件
while (<$rock_fh>) {
	chomp;
	...
}
#输出类型的文件句柄,也可以使用标量变量
open $rock_fh, '>','rock.txt' 
 or die "Could not open rock.txt";
print $rocks_fh "limestone\n";   #没有逗号,用空格分割,print会判断$rocks_fh为文件句柄
print $rocks_fh,"limestone\n";   #使用逗号,print会将$rocks_fh识别为字符串,打印错误信息
print STDOUT;                    #perl可以识别STDOUT为句柄,默认输出$_变量的内容;
print $rocks_fh;                 #perl不能识别$rocks_fh句柄,输出变量$rocks_fh的内容;
print {$rocks_fh} $_;            #我们可以使用{}将文件句柄格式,帮助perl识别。但perl不会默认打印$_中内容,需要手动指明;
print {$rocks[0]} "limestone\n"; #即使文件句柄保存在数组或者哈希中,使用{}隔离之后,perl也能识别它是文件句柄
close $rocks_fh;
  • 建议:
  1. 对于比较小的程序,如脚本文件,使用裸字就足够了;
  2. 对于稍大一些的项目和应用程序,建议使用标量变量,这样可以精确控制文件句柄的作用范围。

猜你喜欢

转载自blog.csdn.net/qq_39556143/article/details/84900049