下述理解,完全是个人体会。自觉有点道理。
perl文件句柄的理解
句柄,又叫指针;下文,我也称之为头地址,因为更形象一些。
文件句柄,就是指向文件内容的内存空间范围的头地址;文件句柄读取一次,起始地址+1,即读取下一行(perl里默认是一行一行读取文本的。可以设置间隔符$/
,使之不是\n
)。这一段,是个人体会,不知正确否。以硬件角度,类似FIFO及FIFO读指针(ps:先入先出,而非堆栈,FILO,先入后出)
qilei@AFAAW-704030720:~$ cat test.txt
a11111
a22222
a33333
a44444
a55555
a66666
a77777
a88888
a99999
a00000
b11111
b22222
b33333
b44444
b55555
b66666
b77777
b88888
b99999
b00000
qilei@AFAAW-704030720:~$ cat simple.pl
#!/usr/bin/perl
use strict;
use warnings;
my $fileh_pos;
open my $fileh,"<", $ARGV[0] or die "error:file can't open";
my $line1=<$fileh>;
print $line1;
my $line2=<$fileh>;
print $line2;
qilei@AFAAW-704030720:~$ ./simple.pl test.txt
a11111
a22222
qilei@AFAAW-704030720:~$
如下面举例,连续两次读取文件句柄$fileh,发现第二次读取文件句柄【特指while(<$fileh>)
】,地址已经递增操作了,而不是从第一行读取test.txt的内容。
qilei@AFAAW-704030720:~$ cat b.pl
#!/usr/bin/perl
use strict;
use warnings;
open my $fileh,"<", $ARGV[0] or die "error:file can't open";
while(<$fileh>){
if($_ =~ /a33333/) {
print $_;
while(<$fileh>){
print $_;
}
}
}
qilei@AFAAW-704030720:~$ ./b.pl test.txt
a33333
a44444
a55555
a66666
a77777
a88888
a99999
a00000
b11111
b22222
b33333
b44444
b55555
b66666
b77777
b88888
b99999
b00000
文本多行匹配的一种算法
网上介绍的一种算法,是基于tell和seek。这个在后面会介绍。
这里的算法,可以看做是基于嵌套循环。ps:根据实际需求,可以灵活使用last和next。
如果在第二次while(<$fileh>)
的时候增加判断条件,就可以依据第一次匹配关键词“a33333”这个前提条件,做第二次匹配。
qilei@AFAAW-704030720:~$ cat b.pl
#!/usr/bin/perl
use strict;
use warnings;
open my $fileh,"<", $ARGV[0] or die "error:file can't open";
while(<$fileh>){
if($_ =~ /a33333/) {
print $_;
while(<$fileh>){
if($_ =~ /7777/) {
print $_;
last;
}
}
}
}
qilei@AFAAW-704030720:~$ ./b.pl test.txt
a33333
a77777
qilei@AFAAW-704030720:~$
seek - reposition file pointer for random-access I/O
定位指针,即记录文件句柄的地址。
可以记录文件句柄的头地址、中间地址、末地址。
seek - perldoc.perl.org
http://perldoc.perl.org/functions/seek.html
tell - get current seekpointer on a filehandle
获取之前定位的指针。
tell - perldoc.perl.org
http://perldoc.perl.org/functions/tell.html
seek和tell一般是配套使用。
下面的例子,包含了seek和tell的用法。而且从另一角度,解释了文件句柄头地址的理解。
例子:连续执行两次while(<$fileh>)
的结果
可以看出,第二次执行while(<$fileh>)
的时候,文件句柄已经读不出任何内容了。
qilei@AFAAW-704030720:~$ cat test.txt
a11111
a22222
a33333
a44444
a55555
a66666
a77777
a88888
a99999
a00000
b11111
b22222
b33333
b44444
b55555
b66666
b77777
b88888
b99999
b00000
qilei@AFAAW-704030720:~$ cat a1.pl
#!/usr/bin/perl
use strict;
use warnings;
open my $fileh,"<", $ARGV[0] or die "error:file can't open";
while(<$fileh>){
if($_ =~ /3333/) {
print $_;
}
}
while(<$fileh>){
if($_ =~ /7777/) {
print $_;
last;
}
}
qilei@AFAAW-704030720:~$ ./a1.pl test.txt
a33333
b33333
qilei@AFAAW-704030720:~$
增加tell和seek的使用
tell的作用,是记录文件句柄的头地址,即位置。
seek有三个参数,
1. 文件句柄;
2. 依据第三个参数,提供相对于头地址的相对位置;
3. 如下:
0代表文件开头的位置。即重新开始,类似先close $fileh
,然后再open $fileh
的效果。
1代表当前头地址的位置;
2代表文件末尾的位置。
qilei@AFAAW-704030720:~$ cat a2.pl
#!/usr/bin/perl
use strict;
use warnings;
my $fileh_pos;
open my $fileh,"<", $ARGV[0] or die "error:file can't open";
while(<$fileh>){
if($_ =~ /3333/) {
$fileh_pos=tell $fileh;
print $_;
}
}
seek($fileh,$fileh_pos,0);
while(<$fileh>){
if($_ =~ /7777/) {
print $_;
last;
}
}
qilei@AFAAW-704030720:~$ diff a1.pl a2.pl
4a5
> my $fileh_pos;
7a9
> $fileh_pos=tell $fileh;
11a14
> seek($fileh,$fileh_pos,0);
qilei@AFAAW-704030720:~$ ./a2.pl test.txt
a33333
b33333
b77777
qilei@AFAAW-704030720:~$
参考文档
Perl特殊变量
http://www.yiibai.com/perl/perl_special_variables.html
Perl参考函数
http://www.yiibai.com/perl/perl_function_references.html