1.文件
1.1open-close
open FILEHANDLE, EXPR
...
open(FILE,"<sim.log") or die "can't open sim.log,$!";
#open(FILE,"<","sim.log") or die "can't open sim.log,$!"; #也可以
#open(FILE,"r","sim.log"); #不支持
while(<FILE>){ #<>为钻石操作符,按行读取文件内容
print "$_\n";
}
close FILE;
#close; #也可以,但不建议,容易出错
EXPR中:
< | 只读(open默认方式),文件指针指向开头;不存在则报错 |
> | 只写,文件指针指向开头;不存在则尝试创建 |
>> | 只写,文件指针指向结尾(追加);不存在则尝试创建 |
+< | 读写,文件指针指向开头,写多少覆盖不少;不存在则报错 |
+> | 读写,文件大小直接截为0;不存在则尝试创建 |
+>> | 读写,文件指针指向结尾;不存在则尝试创建 |
*实测sysopen不能创建文件
*open可以重定向,也可以和管道一起使用,略。
1.2读写文件
<> 文件句柄操作符,<FILEHANDLE>读取句柄指向的文件的内容,标量环境返回一行内容,数组环境返回整个文件内容。<>默认从命令行参数列表@ARGV中的文件中读取内容,@ARGV中若无元素,则从STDIN标准输入文件句柄中读取,也可使用<FILEHANDLE>手动指定句柄。
#from @ARGV
@ARGV = ("sim.log"); #@ARGV可以手动修改,如有多个文件,则逐个读取
while(<>){ #标量环境读取一行
print;
#print "\n";
}
close;
#from STDIN
while(<>){
print "$_\n";
}
print FILEHANDLE list,FILEHANDLE默认为STDOUT,即输出到屏幕,也可指定为普通文件句柄。
open DATA,"+>","sim.log" or die "cannot open it,$!";
open DATA1,"<","hello.pl" or die "cannot open it,$!";
print DATA <DATA1>;
=head
数组环境读取整个文件,也可以先赋给一个数组;
读取内容输出到DATA指向的文件中;
print中,DATA后面没有逗号,逗号是连接符;
=cut
#close; #which FILEHANDLE is closed?强烈不推荐
close DATA1;
=head
fileno:
STDIN, STDOUT和 STDERR 的文件描述符 分别是0,1和 2 (Unix 标准传统),
标准文件输入输出句柄的值从3开始,其具体值由句柄打开的顺序决定。
若某变异 是一个普通变量,则fileno的返回值 是undef;
若某个文件句柄未正常打开或者已关闭,fileno返回的值 也是undef
=cut
print fileno DATA,"\n"; #3 普通文件句柄
print fileno DATA1,"\n"; #undef
print tell DATA,"\n"; #结尾
print tell DATA1,"\n"; #-1,关闭了文件
*rename string1,string2;重命名
*unlink filename1;删除文件
1.3文件位置
tell FILEHANDLE:获取文件当前位置,以字节计;
seek FILEHANDLE, POSITION, WHENCE:移动读写指针,position指定移动的字节数,whence指定移动的起点,0,1,2分别表示文件开头、当前位置,结尾。
sysopen(DATA,"sim3.log",O_RDONLY) or die "can't open sim.log,$!";
#following sysopen doesn't work
#sysopen(DATA2,"./sim2.log",O_WRONLY|O_CREAT,0755) or die "can't create sim2.log,$!";
open DATA2,"+>sim2.log" or die "can't open sim2.log,$!";
while(<DATA>){
print DATA2 $_;#there is no "," between DATA2 and $_
printf "DATA2 position:%d\n",tell DATA2;
#finally,print moves ptr of DATA2 to the end
}
print tell DATA2,"\n";
seek DATA2,0,0; #重定向读写指针到文件开头,否则下面的while无法执行
print tell DATA2,"\n";
while(<DATA2>){
print "in sim2.log: $_\n";
}
1.4文件信息
-A | 文件上一次被访问的时间(单位:天) |
-B | 是否为二进制文件 |
-M | 文件上一次被修改的时间(单位:天) |
-T | 是否为文本文件 |
-d | 为目录 |
-e | 文件或目录名存在 |
-f | 为普通文件 |
-l | 为符号链接 |
-p | 文件是命名管道(FIFO) |
-s | 文件或目录存在且不为0(返回字节数) |
-z | 文件存在,大小为0(目录恒为false),即是否为空文件, |
my $file = "sim.log";
if(-e $file){
say "is a file" if(-f _); #_?
#say "is a file" if(-f); #等于-f $_,但$_不存在
say "is a dir" if(-d _);
}
2.目录
opendir DIRHANDLE, EXPR # 打开目录,打开脚本所在目录可能会出错
readdir DIRHANDLE # 读取目录
rewinddir DIRHANDLE # 定位指针到开头
telldir DIRHANDLE # 返回目录的当前位置
seekdir DIRHANDLE, POS # 定位指定到目录的 POS 位置
closedir DIRHANDLE # 关闭目录
#open DIR,"~/Proj/" or die "can't open dir: .,$!\n"; #不是open,是opendir
opendir DIR,"." or die "can't open dir: .,$!\n";
#way1
=head
标量环境每次循环返回一个文件名,直到遍历目录下所有元素,此时目录指针指向目录结尾,
如果需要再次读,需要rewinddir重定向目录指针到开头位置
=cut
while(readdir(DIR)){
print $_."\n";
}
print "now position:",telldir(DIR),"\n";
rewinddir(DIR);
print "now position:",telldir(DIR),"\n";
my $firstFile = readdir(DIR); #每次返回一个文件名,不是返回元素个数
print "\$firstFile=$firstFile\n";#first file
rewinddir(DIR);
my $fileNum = scalar readdir(DIR); #依然返回第一个元素,不是元素个数!!!
print "\$fileNum=$fileNum\n";#first file too,not array size
rewinddir(DIR);
#way2
my @file = readdir(DIR); #列表环境返回所有元素
foreach(@file){
print $_."\n";#every file
}
close(DIR);
print "now close dir\n";
#way3
opendir DIR,"." or die "can't open dir: .,$!\n";
while($file = readdir(DIR)){ #读出元素的同时,进行赋值
print $file."\n";
}
*mkdir-rmdir-chdir
if(not -e "test"){ #注意引号
mkdir "test" or die "cannot mkdir";
}
opendir DIR,"." or die "cannot open die";
#while(grep /test/,readdir DIR){ #not work
foreach(grep /test/,readdir DIR){ #grep:grep /pattern/,ARRAY
print $_,"\n";
}
chdir "test" or die "cannot chdir";
open(FILE,"+>","test.pl") or die "cannot open it";
system(ls); #output to screen
close DIR;
close FILE;
unlink "test.pl";
rmdir "../test"; #必须是空目录
*glob
相当于shell中的通配符,有2种形式:
1.@files = glob "*.pl";
2.@files = <*.pl>;perl检查<>中是否是句柄,不是则当成glob处理;
#my @file = glob "~/Proj/Perl/*.pl"; #与下句相同
my @file = <~/Proj/Perl/*.pl>;
#my $filestr = "~/Proj/Perl/*.pl"; #<>处理含通配符的变量时,变量需要加{}
#my @file = <${filestr}>;
foreach(@file){
print $_."\n";
}
<>-glob-@ARGV-ARGV-$ARGV
if(@ARGV){
while(<>){ #同while(<ARGV>){,ARGV是@ARGV中的文件名的句柄
say "$ARGV:\t$_"; #$ARGV是当前<>操作的句柄指向的文件名,$_是从文件读出的每一行.
}
}
else{
say "without para"; #若@ARGV为空,则<>从STDIN输入的文件中读取内容。
}
my @paraArray = @ARGV;
printf "\@paraArray:%s\n" x @paraArray,@paraArray;
#when para is not quotated by "". such as diamond.pl *.log
#my @paraExpand = <>; #read all file directly
#foreach(@paraExpand){
# say;
#}
#when para is quotated by "". such as diamond.pl "*.log"
#my @paraExpand = <>; #wrong.
my @paraExpand = <@ARGV>; #here <> is glob operator
foreach(@paraExpand){
#while(<>){ #wrong,<>尝试读取@ARGV中的文件,同<ARGV>,ARGV是@ARGV中文件的句柄
#while(<$_>){ #wrong,<>不能操作文件名.
say ; #every file name,not content
#}
}
printf "%s\n" x @paraExpand,@paraExpand;
my $para = $ARGV[0];
say $para;
my @paraExpand = <${para}>; #glob operator
printf "%s\n" x @paraExpand,@paraExpand;
#my @paraError = <$para>; #file_handle operator
#printf "%s\n" x @paraError,@paraError;
具体参考链接
*shell中不在""内的通配符*,会自动展开,所以如果perl脚本命令行参数是这种形式,实际传进去的是展开后的参数列表。
*find
下面为vim自动补全perl包名的脚本:
#! /usr/bin/perl
use strict;
use warnings;
use File::Find 'find';
#use Smart::Comments;
#补全模块所在文件
my $LIST_DIR = "$ENV{HOME}/.vim_extras/";
my $LIST_FILE = "file_perl_module";
unless(-e $LIST_DIR){
mkdir $LIST_DIR or die "Couldn't create directory $LIST_DIR($!)\n";
}
open my $fh,">","$LIST_DIR$LIST_FILE" or die "Couldn't create file '$LIST_FILE'($!)\n";
my %already_seen;
my @incRev = (qw(/usr/share/perl/5.18.2),@INC); #@INC目录不包含5.18.2目录
for my $incl_dir (@incRev){
print "in dir:$incl_dir\n";
find{
wanted => sub{ #哈希形式:wanted=>匿名子程序引用
my $file = $_; #每次查找返回的文件名,是否包含路径视options而定
return unless $file =~ /\.pm$/;
### 1
### $file #smart comment自动打印变量,注释掉use后不打印
$file =~ s#^\Q$incl_dir/\E##;#非单词加反斜杠,然后删掉不需要的目录前缀
### 2
### $file
$file =~ s{/}{::}g;#::替换/
### 3
### $file
$file =~ s#\.pm\z##;#去掉.pm后缀
### 4
### $file
print {$fh} $file,"\n" unless $already_seen{$file}++;#去重
},
no_chdir => 1,#opt:不进入目录,返回的$_含目录信息,从当前目录开始
},$incl_dir; #也可以直接跟列表
}
#上面的find是下面这种形式,find 匿名哈希引用,搜索路径:
find({ wanted => /&process, follow => 1 }, '.');#follow?
如果不给option,可以进一步简写为这种形式,find 子程序引用,搜索路径:
find(\&func, @Dir);
sub func{
#运用正则进行筛选
};
wanted指向的子程序中,有3个特殊变量:
$File::Find::dir 是当前目录全路径;
$_ 是当前文件名(不含路径);
$File::Find::name 是当前文件的完整路径。
具体参考链接