版权声明:转载请说明出处! 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会贴心的帮我们把原来的文件句柄打开。
- 三要点理解:
- 重新打开某个句柄时,原来已经打开的同名句柄,会被perl自动关闭;
- 尽量不要重用系统的六个默认句柄;
- 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;
- 建议:
- 对于比较小的程序,如脚本文件,使用裸字就足够了;
- 对于稍大一些的项目和应用程序,建议使用标量变量,这样可以精确控制文件句柄的作用范围。