《Perl语言入门》之四――输入与输出

标准输入输出

STDIN可以用于接收键盘输入或是文件输入。在标量上下文中执行该操作时,会返回输入中的下一行。

while <STDIN> {
    chomp;
    print "I saw $_";
}
foreach <STDIN> {
    chomp;
    print;
}

看起来上例中的“while”循环和“foreach”的行为完全一样,其实是有些差别的――在while循环里,Per会读取一行输入,把它存入某个变量并且执行循环的主体,接下来它会回去寻找其他输入行;foreach循环中,行输入操作符会在列表上下文中执行(因为foreach需要逐项处理列表内容),因此Perl会将全部内容读入内存,然后才开始执行循环。当需要处理的输入数据长度很大时,比如处理400M大小的Web服务器日志文件,foreach的效率会比while低很多。因此最好的做法是尽量使用while循环,让它每次处理一行。


钻石操作符的输入<>

钻石操作符提供类似 标准Unix工具程序的参数输入方式,例如对于如下Perl程序“my_program”:

while <> {
    chomp;
    print;
}

如果执行命令“./my_program fred barney betty”,它应该会处理文件fred,接着是barney,最后是betty。(钻石操作符怎么会知道检查命令行参数呢?其实它的参数是来自@ARGV数组)

如果执行命令是没有指定调用参数,程序会从标准输入流采集数据。

当然还有个例外,如果参数中包含连字符“-”,则Perl代码处理到连字符时,会临时改从标准输入读取数据。


使用print/printf/say输出到标准输出

Print操作符会读取后续列表中的所有元素,并把每一项一次送到标准输出。

print <>; #相当于Unix下的cat命令 
print sort <>; #相当于Unix下的sort命令

如果对print的输出格式不够满意,还可以使用printf来产生格式化过的输出结果。

printf "Hello, %s; your password expires in %d days!\n", $user, $days_to_die;

当然Perl一如既往地提供了更方便的格式"%g" (你可以把"g"当成"General"数字转换)。

一般来说,我们编写printf的格式化字符串时已经确定了替换参数的个数和类型,不过万事没有绝对,下面的例子就是用程序在运行时动态产生格式字符串。

my @items = qw( wilma dino pebbles ); 
my $format = "The items are: \n" . ("%10s\n" x @items); 
printf $format, @items;

另外,有个叫Perl Power Tools (PPT)的项目目标就是用perl重写所有经典Unix工具程序,但是在重写shell的时候陷入了难题。PPT项目一度非常有用,因为它使所有便准的工具程序可以运行在非Unix机器上。

Say函数的功能和print的差不多,但在打印每行内容时都会自动加上换行符。所以下面几种写法的输出结果都一样:

use 5.010 
print "Hello!\n"; 
print "Hello!" . "\n"; 
say "Hello!";


文件句柄

一般使用全大写字母来命名文件句柄,但是有6个个数文件句柄是Perl保留的――STDIN、STDOUT、STDERR、DATA、ARGV以及ARGVOUT。

open CONFIG, 'dino'; #打开一个文件 
open CONFIG, '<dino' #只读方式打开一个文件 
open REDROCK, '>fred' #创建一个新的文件,如果已经存在,则清除原有内容并以新内容代替 
open LOG, '>>logfile' #追加方式打开一个文件,如果文件不存在,则创建一个新文件

5.6版的Perl里,加入了open的三个参数的写法:

open CONFIG, '<', 'dono'; 
open BEDROCK, '>', $file_name; 
                                                                         
open CONFG, '<:encoding(UTF-8)', $file_name; #使用UTF-8编码打开文件,这种书写方式会确认编码是否正确 
open BEDROCK, '>:utf8', &logfile_name(); #这种简写的方式不会考虑输入输出的数据是否真的是合法的UTF-8字符串

我们可以通过下面的这条命令打印出说有perl能理解的字符编码清单:

% perl -MEncode -le "print for Encode->encodings(':all')"

除了字符编码之外,数据输入或输出过程中还可以做其他转换操作。比如DOS风格和Unix风格的换行符:

open BEDROCK, '>:crlf', $file_name; #按照DOS换行符风格写入文件 
open BEDROCK, '<:crlf', $file_name; #读取DOS风格的文件



关闭文件句柄

close BEDROCK;


出错处理

当Perl遇到致命错误时,你的程序应该立刻中止运行,并发出错误信息告知原因。这样的功能可以用die函数来实现。

if ( ! open LOG, '>>', 'logfile' ) { 
    die "Cannot create logfile: $!"; #die函数会终止程序的运行并打印出错信息 
}

"$!"代表可读的系统错误信息。一般来说,当系统拒绝我们的请求时,"$!"会给出一个解释,类似于C语言中调用perror取得的字符串。

如果Perl遇到的错误是非致命的,可以使用warn函数送出警告信息。warn函数的功能就是产生类似于Perl的内置警告信息的信息(比如启用警告信息时,使用某个undef变量却将它当成已有的值来参与计算,就会触发警告信息)。


自动检测致命错误

从Perl 5.10开始,为人称道的autodie编译指令已经成为标准库的一部分。

use autodie;

这条编译指令是靠判别具体操作的类型来工作的。如果Perl内置函数调用了操作系统接口的话,那么中途出现的错误并不是编程人员所能控制的,所以一旦发现系统调用出错,autodie便会自动帮你调用die。


使用文件句柄

以写入或添加方式打开文件后,可以直接使用print或printf将字符串输出到文件中:

print LOG "Captain's log, stardate 3.14159"; 
printf STDERR "%d percent complete.\n", $done/$total * 100;

如果print/printf的参数列表没有提供文件句柄,则字符串默认被输出到STDOUT。不过可以使用select操作符改变默认的文件句柄,另外还有一个很奇特的变量"$|",当它的值被设为1,就会使当前的默认句柄在每次输出操作后立刻刷新缓冲区。所以,如果要让输出的内容立即显示(比如在读取监视某个耗时程序的实时日志时),应该这么做:

select LOG; # 将默认输出设定为LOG文件句柄 
$|= 1; # 不要将LOG的内容保留在缓冲区 
select STDOUT; 
print LOG "This gets written to the LOG at once!\n";


你可能感兴趣的:(Perl入门)