open函数
open函数将文件变量与某文件联系起来,提供访问文件的接口,例如:open(MYVAR, "/u/file"); 如果文件打开成功,则返回非零值,否则返回零。缺省地,open打开文件用以读取其内容,若想打开文件以写入内容,则在文件名前加个大于号:open(MYVAR, ">/u/file"); 向已有的文件末尾添加内容用两个大于号:open(MYVAR, ">>/u/file"); 若想打开文件作为数据导向的命令,则在命令前加上管道符(|):open(MAIL, "|mail dave");
用open重定向输入
可以把打开的文件句柄用作向程序输入数据的命令,方法是在命令后加管道符(|),如:
open(CAT, "cat file*|");
对open的调用运行命令cat file* ,此命令创建一个临时文件,这个文件的内容是所有以file打头的文件的内容连接而成,此文件看作输入文件,可用文件变量CAT访问,如:
$input = ;
下面的例子使用命令w的输出来列出当前登录的所有用户名。

1 : #!/usr/local/bin/perl      
2 :      
3 : open (WOUT, "w|");      
4 : $time = <WOUT>;      
5 : $time =~ s/^ *//;      
6 : $time =~ s/ .*//;      
7 : ; # skip headings line      
8 : @users = ;      
9 : close (WOUT);      
10: foreach $user (@users) {      
11:   $user =~ s/ .*//;      
12: }      
13: print ("Current time: $time");      
14: print ("Users logged on:\n");      
15: $prevuser = "";      
16: foreach $user (sort @users) {      
17:   if ($user ne $prevuser) {      
18:     print ("\t$user");      
19:     $prevuser = $user;      
20:   }      
21: }


结果输出如下:

Current time: 4:25pm
Users logged on:
dave
kilroy
root
zarquon

w命令列出当前时间、系统负载和登录的用户,以及每个用户的作业时间和当前运行的命令,如:

4:25pm  up 1 day,  6:37,  6 users,  load average: 0.79, 0.36, 0.28
User     tty       login@  idle   JCPU   PCPU what
dave     ttyp0     2:26pm           27      3 w
kilroy   ttyp1     9:01am  2:27   1:04     11 -csh
kilroy   ttyp2     9:02am    43   1:46     27 rn
root     ttyp3     4:22pm     2               -csh
zarquon  ttyp4     1:26pm     4     43     16 cc myprog.c
>kilroy   ttyp5     9:03am         2:14     48 /usr/games/hack

上例中从w命令的输出中取出所需的信息:当前时间和登录的用户名。第3行运行w命令,此处对open的调用指定w的输出用作程序的输入,用文件变量WOUT来访问该输入。第4行读取第一行信息,即:
4:25pm up 1 day, 6:37, 6 users, load average: 0.79, 0.36, 0.28
接下来的两行从这行中抽取出时间。首先,第5行删除起始的空格,然后第6行删去除时间和结尾换行符之间的所有字符,存入变量$time。
第7行从WOUT读取第二行,这行中无有用信息,故不作处理。第8行把剩下的行赋给数组@users,然后第9行关闭WOUT,终止运行w命令的进程。
@users中的每个元素都是一行用户信息,因为本程序只需要每行的第一个单词,即用户名,故10~12行去掉除换行符外的其它字符,这一循环结束后,@users中只剩下用户名的列表。
第13行输出存贮在$time中的时间,注意这时print不需要加上换行符,因为$time中有。16~21行对@users中的用户名排序并输出。因为同一个用户可以多次登录,所以用$preuser存贮输出的最后一个用户名,下次输出数组元素$user时,如果其与$preser相等,则不输出。
文件重定向
许多UNIX shell可以把标准输出文件(STDOUT)和标准错误文件(STDERR)都重定向到同一个文件,例如在Bourne Shell(sh)中,命令
$ foo > file1 2>&1
运行命令foo并把输出到标准输出文件和标准错误文件的内容存贮到文件file1中。下面是用Perl实现这一功能的例子:

1: #!/usr/local/bin/perl
2:
3: open (STDOUT, ">file1") || die ("open STDOUT failed");
4: open (STDERR, ">&STDOUT") || die ("open STDERR failed");
5: print STDOUT ("line 1\n");
6: print STDERR ("line 2\n");
7: close (STDOUT);
8: close (STDERR);

运行后,文件file1中的内容为:
line 2
line 1
可以看到,这两行并未按我们想象的顺序存贮,为什么呢?我们来分析一下这段程序。
第3行重定向标准输出文件,方法是打开文件file1将它与文件变量STDOUT关联,这也关闭了标准输出文件。第4行重定向标准错误文件,参数>&STDOUT告诉Perl解释器使用已打开并与STDOUT关联的文件,即文件变量STDERR指向与STDOUT相同的文件。第5、6行分别向STDOUT和STDERR写入数据,因为这两个文件变量指向同一个文件,故两行字符串均写到文件file1中,但顺序却是错误的,怎么回事呢?
问题在于UNIX对输出的处理上。当使用print(或其它函数)写入STDOUT等文件时,UNIX操作系统真正所做的是把数据拷贝到一片特殊的内存即缓冲区中,接下来的输出操作继续写入缓冲区直到写满,当缓冲区满了,就把全部数据实际输出。象这样先写入缓冲区再把整个缓冲区的内容输出比每次都实际输出所花费的时间要少得多,因为一般来说,I/O比内存操作慢得多。
程序结束时,任何非空的缓冲区都被输出,然而,系统为STDOUT和STDERR分别维护一片缓冲区,并且先输出STDERR的内容,因此存贮在STDERR的缓冲区中的内容line 2出现在存贮在STDOUT的缓冲区中的内容line 1之前。
为了解决这个问题,可以告诉Perl解释器不对文件使用缓冲,方法为:
1、用select函数选择文件
2、把值1赋给系统变量$|
系统变量$|指定文件是否进行缓冲而不管其是否应该使用缓冲。如果$|为非零值则不使用缓冲。$|与系统变量$~和$^协同工作,当未调用select函数时,$|影响当前缺省文件。下例保证了输出的次序:

1 : #!/usr/local/bin/perl
2 :
3 : open (STDOUT, ">file1") || die ("open STDOUT failed");
4 : open (STDERR, ">&STDOUT") || die ("open STDERR failed");
5 : $| = 1;
6 : select (STDERR);
7 : $| = 1;
8 : print STDOUT ("line 1\n");
9 : print STDERR ("line 2\n");
10: close (STDOUT);
11: close (STDERR);

程序运行后,文件file1中内容为:
line 1
line 2
第5行将$|赋成1,告诉Perl解释器当前缺省文件不进行缓冲,因为未调用select,当前的缺省文件为重定向到文件file1的STDOUT。第6行将当前缺省文件设为STDERR,第7行又设置$|为1,关掉了重定向到file1的标准错误文件的缓冲。由于STDOUT和STDERR的缓冲均被关掉,向其的输出立刻被写到文件中,因此line 1出现在第一行。
指定读写权限
打开一个既可读又可写的文件方法是在文件名前加上"+>",如下:
open (READWRITE, "+>file1");
此语句打开既可读又可写的文件file1,即可以重写其中的内容。文件读写操作最好与库函数seek和tell一起使用,这样可以跳到文件任何一点。
注:也可用前缀"+<"指定可读写权限。
close函数
用于关闭打开的文件。当用close关闭管道,即重定向的命令时,程序等待重定向的命令结束,如:
open (MYPIPE, "cat file*|");
close (MYPIPE);
当关闭此文件变量时,程序暂停运行,直到命令cat file*运行完毕。
print, printf和write函数
print是这三个函数中最简单的,它向指定的文件输出,如果未指定,则输出到当前缺省文件中,如:
print ("Hello, there!\n");
print OUTFILE ("Hello, there!\n");
第一句输出到当前缺省文件中,若未调用select,则为STDOUT。第二句输出到由文件变量OUTFILE指定的文件中。
printf函数先格式化字符串再输出到指定文件或当前缺省文件中,如:
printf OUTFILE (“You owe me %8.2f", $owing);
此语句取出变量$owing的值并替换掉串中的%8.2f,%8.2f是域格式的例子,把$owing的值看作浮点数。
write函数使用输出格式把信息输出到文件中,如:
select (OUTFILE);
$~ = "MYFORMAT";
write;
关于printf和write,详见《第x章 格式化输出》。
select函数
select函数将通过参数传递的文件变量指定为新的当前缺省文件,如:
select (MYFILE);
这样,MYFILE就成了当前缺省文件,当对print、write和printf的调用未指定文件时,就输出到MYFILE中。
eof函数
eof函数查看最后一次读文件操作是否为文件最后一个记录,如果是,则返回非零值,如果文件还有内容,返回零。
一般情况下,对eof的调用不加括号,因为eof和eof()是等效的,但与<>操作符一起使用时,eof和eof()就不同了。现在我们来创建两个文件,分别叫做file1和file2。file1的内容为:
This is a line from the first file.
Here is the last line of the first file.
file2的内容为:
This is a line from the second and last file.
Here is the last line of the last file.
下面就来看一下eof和eof()的区别,第一个程序为:

1: #!/usr/local/bin/perl      
2:      
3: while ($line = <>) {      
4:   print ($line);      
5:   if (eof) {      
6:     print ("-- end of current file --\n");      
7:   }      
8: }


运行结果如下:

$ program file1 file2
This is a line from the first file.
Here is the last line of the first file.
-- end of current file --
This is a line from the second and last file.
Here is the last line of the last file.
-- end of current file --
$

下面把eof改为eof(),第二个程序为:      

1: #!/usr/local/bin/perl      
2:      
3: while ($line = <>) {      
4:   print ($line);      
5:   if (eof()) {      
6:     print ("-- end of output --\n");      
7:   }      
8: }


运行结果如下:

$ program file1 file2
This is a line from the first file.
Here is the last line of the first file.
This is a line from the second and last file.
Here is the last line of the last file.
-- end of output --$

这时,只有所有文件都读过了,eof()才返回真,如果只是多个文件中前几个的末尾,返回值为假,因为还有要读取的输入。
间接文件变量
对于上述各函数open, close, print, printf, write, select和eof,都可以用简单变量来代替文件变量,这时,简单变量中所存贮的字符串就被看作文件变量名,下面就是这样一个例子,此例很简单,就不解释了。需要指出的是,函数open, close, write, select和eof还允许用表达式来替代文件变量,表达式的值必须是字符串,被用作文件变量名。

1: #!/usr/local/bin/perl      
2:      
3: &open_file("INFILE", "", "file1");      
4: &open_file("OUTFILE", ">", "file2");      
5: while ($line = &read_from_file("INFILE")) {      
6:   &print_to_file("OUTFILE", $line);      
7: }      
8:      
9: sub open_file {      
10:   local ($filevar, $filemode, $filename) = @_;      
11:      
12:   open ($filevar, $filemode . $filename) ||      
13:  &n      
die ("Can't open $filename");      
14: }      
15: sub read_from_file {      
16:   local ($filevar) = @_;      
17:      
18:   <$filevar>;      
19: }      
20: sub print_to_file {      
21:   local ($filevar, $line) = @_;      
22:      
23:   print $filevar ($line);      
24: }



2、跳过和重读数据


函数名 seek
调用语法 seek (filevar, distance, relative_to);
解说 在文件中向前/后移动,有三个参数:
1、filevar,文件变量
2、distance,移动的字节数,正数向前移动,负数往回移动
3、reletive_to,值可为0、1或2。为0时,从文件头开始移动,为1时,相对于当前位置(将要读的下一行)移动,为2时,相对于文件末尾移动。
运行成功返回真(非零值),失败则返回零,常与tell函数合用。

函数名 tell
调用语法 tell (filevar);
解说 返回从文件头到当前位置的距离。
注意:
1、seek和tell不能用于指向管道的文件变量。
2、seek和tell中文件变量参数可使用表达式。
3、系统读写函数

函数名 read
调用语法 read (filevar, result, length, skipval);
解说 read函数设计得与UNIX的fread函数等效,可以读取任意长度的字符(字节)存入一个简单变量。其参数有四个:
1、filevar:文件变量
2、result:存贮结果的简单变量(或数组元素)
3、length:读取的字节数
4、skipval:可选项,指定读文件之前跳过的字节数。
返回值为实际读取的字节数,如果已到了文件末尾,则返回零,如果出错,则返回空串。

函数名 sysread
调用语法 sysread (filevar, result, length, skipval);
解说 更快的读取数据,与UNIX函数read等效,参数与read相同。

函数名 syswrite
调用语法 syswrite (filevar, data, length, skipval);
解说 更快的写入数据,与UNIX函数write等效,参数:
1、filevar:将要写入的文件
2、data:存贮要写入数据的变量
3、length:要写入的字节数
4、skipval写操作之前跳过的字节数。
4、用getc读取字符

函数名 getc
调用语法 $char = getc (infile);
解说 从文件中读取单个字符。
5、用binmode读取二进制文件

函数名 binmode
调用语法 binmode (filevar);
解说 当你的系统(如类DOS系统)对文本文件和二进制文件有所区别时使用。必须在打开文件后、读取文件前使用。



 



 



=======================================================================





perl几个读取文件命令测试比较,仅供参考



2007年07月06日 星期五 上午 10:03







 

读取文件命令测试比较,仅供参考   ;

因为文件行数少了测试不出来效果,我特意做了包含整1万行的数据,大小170K。

本机雷鸟1.1GHZ,内存256兆,IIS5.0 perliisdll环境

####################            
方案一 while 输出   最常用            

open (FILES, "index");            
while (<FILES>){            
print;            
}            
close(FILES);            
程序占用 CPU 时间:0.23 usr + 0.22 sys 合计运行时间 450 毫秒            
#######################            
方案二: 数组读取输出            
open (FILES, "index");            
@reads=<FILES>;            
print @reads;            


程序占用 CPU 时间:4.18 usr + 0.09 sys 合计运行时间 4270 毫秒 这个方法也常用,但效率最低的            

换为@_;            
open (FILES, "index");            
@_=<FILES>;            
print @_;            
程序占用 CPU 时间:3.64 usr + 0.11 sys 合计运行时间 3750 毫秒 节省一点时间:)            

################################            
方案三:            

open (FILES, "index");            
@_=<FILES>;            

#print @_;            
close(FILES);            
foreach (@_){            
print;            
}            

程序占用 CPU 时间:3.79 usr + 0.15 sys 合计运行时间 3940 毫秒            
很奇怪,和上面相同,说明,只要打印数组,就和foreach处理方式相同            
##############################            
方案4 不打印            
open (FILES, "index");            
@_=<FILES>;            
#print @_;              
close(FILES);            
程序占用 CPU 时间:3.45 usr + 0.00 sys 合计运行时间 3450 毫秒 还是相同            
更奇怪,少一次循环,为什么时间还相同            

#########################################            
方案6,用变量代替数组直接读取输出。            

open (FILES, "index");            
$/="";            
$reads=<FILES>;            
print $reads;            
close(FILES);            
$/="\n";            

程序占用 CPU 时间:0.04 usr + 0.00 sys 合计运行时间 40 毫秒 真快丫            

##############################################            
方案7 用分割变量来从新生成数组,代替数组@_=<FILES> 直接读取方式,循环输出            
open (FILES, "index");            
$/="";            
$reads=<FILES>            

close(FILES);            
$/="\n";            

@_=split ( /\n/,$reads);            
foreach (@_){            
print $_;            
}



程序占用 CPU 时间:0.34 usr + 0.11 sys 合计运行时间 450 毫秒

有趣,比普通@_=<FILES> 直接读的方法要快10倍,但很是不解

如果数组不全部输出,单纯赋值占用时间很短

open (FILES, "index");            
$/="";            
$reads=<FILES>            

close(FILES);            
$/="\n";            

@_=split ( /\n/,$reads);



程序占用 CPU 时间:0.05 usr + 0.00 sys 合计运行时间 50 毫秒

###############################################

散列  
--------------------------------------------------------------------------------

open (FILES, "index");            
while (<FILES>){$i++;            
$hash{$i}=($_)            
}            
print %hash;            

close(FILES);




程序占用 CPU 时间:0.66 usr + 0.41 sys 合计运行时间 1070 毫秒

数组的最快方式是450毫秒,散列全部输出时间大概比数组慢一倍

散列不输出            
open (FILES, "index");            
while (<FILES>){$i++;            
$hash{$i}=($_)            

}            
#print %hash;            

close(FILES);            
程序占用 CPU 时间:0.09 usr + 0.04 sys 合计运行时间 130 毫秒   还是比数组慢            

从hash中取出一个元素            

open (FILES, "index");            
while (<FILES>){$i++;            
$hash{$i}=($_)            
}            
close(FILES);            
print $hash{8900};



程序占用 CPU 时间:0.13 usr + 0.00 sys 合计运行时间 130 毫秒 几乎不增加时间

数组也是,测不出时间

open (FILES, "index");            
$/="";            
$reads=<FILES>;            

close(FILES);            
$/="\n";            

@_=split ( /\n/,$reads);            

print $_[8900];            

程序占用 CPU 时间:0.05 usr + 0.00 sys 合计运行时间 50 毫秒            
##########################


以上测试结果有的差别很大,有的差别不大。

即使有些差别虽然是细微的,程序中如果把这些命令都采用最优化方式,相信会有效果的

我最近在把我的论坛调用比较频繁的核心代码进行逐行检查,反复测试优化中~~~~

谁把其他的方法都测试以下,拿出来给爱好者继续分享,我也继续测试中,今晚测试系统级IO命令,看有没有差别

仅供参考。

附,my测试方法            
#########################            
use CGI::Carp qw(fatalsToBrowser);            
use Benchmark;            
$TT0 = new Benchmark;            
print "Content-type: text/html\n\n";            
open (FILES, "index");            
$/="";            
   $reads=<FILES>;            

close(FILES);            
$/="\n";            

@_=split ( /\n/,$reads);            
    print @_;            

###########################            
print"<hr>";            
$TT1 = new Benchmark;            
$td = Benchmark::timediff($TT1, $TT0);            
$td = Benchmark::timestr($td);            
$td =~ /(\d+)\s*wallclock secs \(\s*?(\d*?\.\d*?)\s*usr\s*\+\s*(\d*?\.\d*?)\s*sys/i;            
my $alltimas=($2+$3)*1000;            
print "<center><font color=$cpudispcolor>程序占用 CPU 时间:$2 usr + $3 sys 合计运行时间 $alltimas 毫秒";            

exit;

 

========================================================================
at=2009-11-20 11:48:53<|>aip=122.....
# my %m = &getGMap;
# print $m{"asid"},"\t",$m{"at"},"\n" if not $m{"asid"} eq "" ;
sub getGMap{
 my @arr = split /<\|>/;
 my %h;
 foreach $d (@arr){
   if($d=~/(.*?)=(.*)/){
    $h{$1}=$2;
   }
 }
 return %h;
}

 
# perl -e '
# BEGIN{ require("/data/shell/gmodel/inc_model/utils.pl"); } 
# print &diffTime("2009-12-04 16:58:38","2009-12-04 16:58:00");
# '
sub diffTime{
 use Time::Local;
 my($st1,$st2) = @_; 
 my $t1=timelocal($6,$5,$4,$3,$2-1,$1-1900) if $st1=~/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})/;
 my $t2=timelocal($6,$5,$4,$3,$2-1,$1-1900) if $st2=~/(\d{4})-(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})/;
 return $t1-$t2;
}




# perl -e '
# BEGIN{ require("/data/shell/gmodel/inc_model/utils.pl"); } 
# print &getAgoday(-3);
# #2009-12-31
# print &getAgoday(3);
# #...
# '
sub getAgoday{
 my $nt=$_[0];
 $nt = 1 if $nt !~ /(\-)*\d+/;
 $nt=`date -d "\$[$nt*-1] day" +%Y-%m-%d` if $nt ne "";
 chomp $nt;
 return $nt;
}
# print 23

sub getAgohour{
 my ($nt)=@_;
 $nt = 1 if $nt !~ /(\-)*\d+/;
 $nt=`date -d "\$[$nt*-1] hour" +%H`;
 chomp $nt;
 return $nt;
}
$_vtime=&getAgoday();
$_htime=&getAgohour();
sub setVTime{
 $_vtime=$_[0];
 $_htime=$_[1] if $_[1] ne "";
}



# perl -e '
# BEGIN{ require("/data/shell/gmodel/inc_model/utils.pl"); } 
# # &setVTime('2010-11-12','23');
# print &getConf("logSou","audiobooks_logSou")
# '
use Config::Tiny;
$_Config=Config::Tiny->read("/data/shell/gmodel/inc_model/model.conf");
sub getConf{
 my ($_Y,$_M,$_D)=split /-/,$_vtime;
 my $_H = $_htime ;
 %rp = ("\@Y", $_Y,
       "\@M" , $_M,
       "\@D", $_D,
       "\@H", $_H );
 # 需要 cpan>install Config::Tiny
 my ($group,$key)=@_;
 my $ss=$_Config->{$group}->{$key};
 while (($key, $value) = each(%rp)){
    $ss=~s/$key/$value/g;
 }
 return $ss;
}


my $_filtered_ip=&getConf("filter","filtered_ip");
my @_filtered_ips=split(",", $_filtered_ip );
my $_filtered_aop=&getConf("filter","filtered_aop");
my @_filtered_aops=split(",", $_filtered_aop );
my $_permission_app=&getConf("filter","permission_app");
my @_permission_apps=split(",", $_permission_app );

sub my_filter{
 my %m=%{$_[0]};
 return 0 if $m{auid} eq "" or $m{ab} eq "";
 my @aip=split /,/,$m{aip};
 return 0 if(grep {$_ eq $m{aip} } @_filtered_ips);
 return 0 if(grep {$m{ab} eq $_} @_filtered_aops);
 
 if(not (grep {"ALL" eq $_} @_permission_apps) ){
  if (not (grep {$m{aop} eq $_} @_permission_apps)){
    return 0;
  }
 }
 return 1 ;
}

return 1;