文件和文件句柄
Scalar变量除了能够包含数值、字符串、引用或者undef
,还能包含一个文件句柄。文件句柄本质上就是对于某个文件中某个位置的引用。
用[open](http://perldoc.perl.org/functions/open.html)
可以把一个scalar变量编程文件句柄。我们必须给open
提供一个打开模式。模式<
表示我们想要读取这个文件:
my $f = "text.txt";
my $result = open my $fh, "<", $f;
if(!$result) {
die "Couldn't open '".$f."' for reading because: ".$!;
}
如果成功,open
返回true,否则返回false,并且错误消息会被填入内置变量$!
。就像你在上面的代码里看到的,你总是应该检查open
操作是否成功完成了,不过像那样检查真是冗长乏味,更常见的写法是:
open(my $fh, "<", $f) || die "Couldn't open '".$f."' for reading because: ".$!;
注意,你需要在open
的参数列表两边加上括号。
要从文件句柄中读取一行,可以用内置函数[readline](http://perldoc.perl.org/functions/readline.html)
,readline
返回一整行文本,并且结尾有一个换行符(除了文件末尾的那行可能例外),如果已经读到文件末尾则返回undef
。
while(1) {
my $line = readline $fh;
last unless defined $line;
# 处理$line...
}
可以用[chomp](http://perldoc.perl.org/functions/chomp.html)
移除末尾可能存在的换行符:
chomp $line;
请注意,chomp
直接作用于$line
上,因此$line = chomp $line
可能不会得到你想要的东西。
你也可以用[eof](http://perldoc.perl.org/functions/eof.html)
来检测是否已经读到文件末尾:
while(!eof $fh) {
my $line = readline $fh;
# 处理$line...
}
不过使用while(my $line = readline $fh)
的时候要小心了,因为如果$line
的内容恰好是"0"
,循环可能过早结束。如果你想要这样写,Perl提供了<>
功能上更安全的运算符,你可以用它包围readline
。这种写法很常见而且也非常安全:
while(my $line = <$fh>) {
# 处理$line...
}
甚至:
while(<$fh>) {
# 处理$_...
}
如果要写一个文件,首先你需要另一种打开模式。模式>
表示我们想要写入这个文件。(如果目标文件存在的话,>
会清空它,如果你只是想附加在文件的原有内容后面,你应该用模式>>
。)然后,将文件句柄作为print
方法的第0个参数提供就行了。
open(my $fh2, ">", $f) || die "Couldn't open '".$f."' for writing because: ".$!;
print $fh2 "The eagles have left the nest";
请注意在$fh2
和后面的参数之间没有逗号。
文件句柄在超出它们的作用域以后会自动关闭,如果你想主动关闭:
close $fh2;
close $fh;
有三个文件句柄以全局常量形式存在:STDIN
、STDOUT
和STDERR
,它们在脚本开始时就被自动打开。要读取一行用户的输入:
my $line = <STDIN>;
如果只是等待用户按回车:
<STDIN>;
调用<>
而不提供文件句柄参数,表示从STDIN
或者在Perl脚本启动时指定的参数指向的文件中读取。
你可能已经知道了,如果不提供文件句柄,print
默认会打印到STDOUT
。
文件检测
内置函数-e
用于测试文件是否存在。
print "what" unless -e "/usr/bin/perl";
内置函数-d
用于测试文件是否是目录。
内置函数-f
用于测试文件是否是普通文件。
这只是一大波形如-X
的函数中的三个,其中X
是某些小写或大写字母。这类函数被称作文件检测函数。请注意字母前面的减号,用Google搜索的时候,减号表示从搜索结果中排除包含这个词的结果,这样就导致很难用Google搜索文件检测函数了!用“Perl file test”来搜索就好。