文件测试

版权声明:转载请说明出处! https://blog.csdn.net/qq_39556143/article/details/85219435

文件测试

1. 文件测试操作符

perl提供了一组用于测试文件的操作符,借此可以返回特定的文件信息。

  • 通常使用 -x的形式调用,其中x值得时特定的测试操作,如-w -r等。
  • 通过特定的文件测试符,可以让我们的程序变得更加智能。
  • 使用格式: -r $filename (连字符+测试场景 文件名称或文件句柄)
  • 默认检查$_,但是-t 的默认值是STDIN
#!/usr/bin/perl
#使用-e判断文件是否存在
#如果文件存在,调用die函数结束程序,这样可以保证已存在的文件不会被覆盖
die "Oops! A file call '$filename' already exists.\n"
	if -e $filename;
#测试某个文件是否保持更新
#这里的-M返回的是文件最后一次修改时间到让当前程序启动时刻之间的天数
warn "Config file is looking pretty old.\n"
	if -M CONFIG > 20;
#如果我们希望查找文件大于100k,并且超过90天未访问的文件
my @original_files = qw/fred betty barney wilma pebbles dino/;
my @big_old_files;
foreach my $filename (@original_files) {
	push @big_old_files,$filename
		if -s $filename > 100_000 and -A $filename > 90;  # -s 返回的是以字节计算的文件大小
}

表1.1 文件测试操作符及其意义

文件测试符 意义
-r 文件或目录,对目前(有效的)用户或组来说是可读的
-w 文件或目录,对目前(有效的)用户或组来说是可写的
-x 文件或目录,对目前(有效的)用户或组来说是可执行的
-o 文件或目录,由目前(有效的)用户拥有
-R 文件或目录,对实际的用户或组来说是可读的
-W 文件或目录,对实际的用户或组来说是可写的
-X 文件或目录,对实际的用户或组来说是可执行的
-O 文件或目录,由实际的用户拥有
-e 文件或目录,是存在的
-z 文件或目录存在而且没有内容(对目录来说永远是假)
-s 文件或目录存在并且有内容(返回值是以字节为单位的文件大小)
-f 是否为普通文件
-d 是否为目录文件
-l 是否为符号链接
-S 是否为socket类型的文件
-p 是否为命名管道,即FIFO队列
-b 是否为块设备(比如某个挂载的网盘)
-c 是否为字符设备文件(比如某个IO设备)
-u 文件和目录设置了setuid位
-g 文件和目录设置了setgid位
-k 文件和目录设置了setcky位
-t 文件句柄是TTY设备
-T 看起来像是文本文件
-B 看起来像是二进制文件
-M 最后一次修改至今的天数
-A 最后一次访问至今的天数
-C 最有一次文件节点编号变更至今的天数

注:

  1. 如无特殊声明,返回的都是布尔真/假值;
  2. -r -w -x -o需要查看用户ID,看他们是否具有相应的文件权限;
  3. 有效用户:负责运行这个程序的人。

1.1 同一文件的多个属性测试

如果要一次性测试一个文件的多个属性,可以将个文件的测试组成一个逻辑表达式。

#!/usr/bin/perl
#检查可读可写的文件
if (-r $filename and -w $filename) {
... }
#使用虚拟文件句柄_ (是的就是下划线字符)
if (-r $filename and -w _) {        # _告诉perl使用上次查询过的文件信息做测试
... }
# _ 指的是调用 _ 之前最后一次查询的文件信息
if (-r $filename) {
...}
&lookup ($other_filename);
if(-w _){                          #此时查询的是$other_filename是否具有写权限
...}
sub lookup{
	return -w $_[0]}

1.2 栈式文件测试操作符

perl5.10之后允许使用栈式文件测试操作符。

  • 格式: 将文件测试符排成一列,放在被测试的文件名前
#!/usr/bin/perl
#续上例
if (-w -r $filename){              #注意:这里先检查 -r 再检查 -w,顺序由右向左依次执行
...}
#也可以使用更多的文件测试操作符
if (-w -r -o -x -d $filename){     #顺序由右向左依次执行
...}
#对于需要返回其他值的文件测试符而言,栈式文件操作符反而鸡肋
if (-s -d $filename < 512) {               #错误!
}
if ((-d $filename and -s _) < 512) {       #以上程序和此句一致,当-d为假,永远小于512,if判断条件为真
}
if (-d $filename and -s _ < 512){          #此时建议使用这种写法,因为-s是返回以字节计算的文件大小
...}

2. stat 和 lstat函数

使用文件测试操作符可以查看文件的许多属性,但是还有许多其他属性信息没有对应的文件测试操作符。比如说,没有任何文件测试符会返回文件链接数或者文件拥有者的ID(uid),此时可以使用stat函数,和Unix中的stat类似,返回丰富的文件信息。

  • stat函数:

    • 格式:stat($filename)
    • 参数允许格式:文件句柄,虚拟文件句柄_,返回文件名的表达式
    • 如果执行失败(无效文件名,文件不存在等),函数返回空列表
    • 如果执行成功,返回一个包含13个数字元素的列表。
    • my($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = state($filename)
  • 表2.1 stat函数的返回值

序号 参数 含义
1 $dev 文件所在设备的编号
2 $ino 文件的 inode 编号
3 $mode 文件的权限位集合( -rwxr-xr-- 这种)
4 $nlink 文件或者目录的硬链接数(不包括软连接) (目录一般大于2,文件一般等于1)
5 $uid 文件所有者的用户ID
6 $gid 文件所有者所在组的ID
7 $size 以字节为单位的文件大小和 文件测试操作符 -s 返回结果一致
8 $atime 三种不同纪元(epoch) 算起的秒数的时间戳之一
9 $mtime 三种不同纪元(epoch) 算起的秒数的时间戳之一
10 $ctime 三种不同纪元(epoch) 算起的秒数的时间戳之一
  • 注意:
    • 如果stat的参数是符号链接,那么stat返回文件属性并非符号链接本身,而是其指向的对象;
    • 如果需要查询符号链接的文件属性,可以使用 lstat 函数,如果 lstat 的参数不是符号链接,返回空列表
    • stat 和 lstat 函数的默认操作数是 $_
  • localtime函数
    从state返回的时间值格式可能是1231253675416类似的形式,这样的数字可读性较差,所以我们希望使用比较容易阅读的形式,如: Sat Jan 20 00:54:09 2018这种,Perl中可以在标量上下文中实现这种转换:
#!/usr/bin/perl
my $timestamp = 1234432456;
my $date = localtime $timestamp;
#不提供参数时,默认使用当前time返回的时间值
my $time = localtime;
#类似的还有gmtime,返回世界标准时间,格林威治标准时间
my $time = gmtime;
  • localtime的返回列表:
    • my = ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime $timestamp;

表2.2 local函数的部分返回值

参数 意义
$mon 返回0~11用于索引月份名
$year 返回从1900年算起的年数,+1900就是现在的年数
$wday 返回0~6用于索引星期名
$yday 返回今年的第几天,范围是0~365

3. 位运算操作符

位运算符对数据执行二进制数学运算。

  • 表3.1 位运算操作符及其意义
表达式 意义 (10 = 1010 12 = 1100)
10 & 12 按位与,结果为1000 -> 8
10 | 12 按位或,结果为1110 -> 14
10 ^ 12 按位异或,结果为0110 -> 6
10 << 2 按位左移,结果为101000 -> 40,低位补零
12 >> 2 按位右移,结果为11 -> 3,丢弃移除位
~10 按位取反,结果为0101 -> 5

3.1 使用位字符串

所有的位运算符既可以操作位字符串,也可以操作整数;

  • 如果两个操作数都是整数,那么结果也是整数,如10 & 12 = 8
  • 如果两个操作数都是字符串,那么结果也是字符串,如"\xAA" | “\x55” = “\xFF”
    在perl5.22之前,只要操作数中某一个是数字类型,那么就会按照数字的位运算方式执行;
#!/usr/bin/perl
my $number  = 137;
my $number_str = '137';
my $string  = 'Amelia';
say "number_str & string",$number_str & $string;       #打印:number_str & string ?!%
say "number & string    ",$number     & $string;       #打印:number & string     0
say "number & number_str",$number     & $number_str;   #打印:number & number_str 137
say "number_str & string",$number_str & $string;       #打印:number_str & string 0
#Lin1: 字符串运算得到的结果
#Lin2:因为number是数字,因此先把Amelia转换为数字,然后按照数字方式进行位运算得到0
#Line3:因为number是数字,因此先把‘137’转换为数字,然后按照数字方式进行位运算得到137
#Line4:perl上次处理string和number_str的时候将其修改了他们为数字类型,最后发现两个数字类型进行比较得到0
  • 注:
  1. 其实Perl中有双值变量的概念(dualvar),标量可以具有两个版本的值,数字+字符串;
  2. 大部分时候不会出现问题,反而更加方便;
  3. 如 $! 的字符串版本是返回错误消息,而数字版本是返回错误代号。

Perl5.22以后增加了实验性的新特性已解决类似的奇怪问题,在使用操作符进行是运算时,我们最好能够确定以何种方式进行计算,不管操作数之前的操作历史。在编译时使用bitwise属性即可。

#!/usr/bin/perl
use feature qw(bitwise);
no warning qw(experimental::bitwise);
#全部当做数字进行计算
my $number  = 137;
my $number_str = '137';
my $string  = 'Amelia';
say "number_str & string",$number_str & $string;        #打印:number_str & string 0
say "number & string    ",$number     & $string;        #打印:number & string     0
say "number & number_str",$number     & $number_str;    #打印:number & number_str 137
say "number_str & string",$number_str & $string;        #打印:number_str & string 0
#在操作符后加一个.字符,进行表示以字符串方式进行位运算,如 &.
say "number_str & string",$number_str &. $string;       #打印:number_str & string ?!%
say "number & string    ",$number     &. $string;       #打印:number & string     ?!%
say "number & number_str",$number     &. $number_str;   #打印:number & number_str 137
say "number_str & string",$number_str &. $string;       #打印:number_str & string ?!%

猜你喜欢

转载自blog.csdn.net/qq_39556143/article/details/85219435