Learning Perl 学习笔记 Ch12 文件测试和按位操作

  1. Perl提供了一组文件测试操作符,可以测试文件的各种属性。文件测试操作符看起来像是由一个连字符-一个字母组成的,操作符的作用对象可以是表示文件名的字符串变量,也可以是文件句柄。 文件测试操作符一般返回的都是布尔值,但也有的会返回有实际意义的值(-s)。
    demo12-1
#!/usr/bin/perl
#测试文件是否存在,并且是否在今天修改过
print "Please type in filename: ";
chomp($filename = <STDIN>);
if(-e $filename){
    print "A file called '$filename' already exists.\n";
    open DEMOFILE, $filename;
    if(-M DEMOFILE >= 1){
        print "The file $filename modified before today\n"
    }else{
        print "The file $filename modified today\n";
    }
}else{
    die "Oops! A file called '$filename' doesn't exist.\n";
}
./demo12-1
Please type in filename: demo12-1
A file called 'demo12-1' already exists.
The file demo12-1 modified today
文件测试操作符 意义
-r/w/x/o 文件或目录,对目前用户或组是可读/可写/可执行/拥有的
-R/W/X/O 文件或目录,对实际用户或组是可读/可写/可执行/拥有的
-e 文件或目录,是存在的
-z 文件存在且没有内容(对目录来说永远为假)
-s 文件或目录存在且有内容(返回以字节为单位的文件大小)
-f/d/l/S/p/b/c 是普通文件/目录/符号链接/socket类型文件/命名管道(先入先出队列)/块设备文件/字符设备文件
-u/g//k 文件或目录设置了setuid/setgid/sticky位
-t 文件句柄是TTY设备(类似系统函数isatty();不能对文件名进行此测试)
-T 看起来像文本文件
-B 看起来像二进制文件
-M 返回最后一次修改后至今的天数
-A 返回最后一次访问后至今的天数
-C 返回最后一次文件节点编号(inode)变更后至今的天数
  • -f/d/l/S/p/b/c对应着Unix文件系统的七种文件类型,在非Unix系统上,有的测试可能就没有意义
  • -M/A/C被称为文件时间测试操作符,返回的是换算成天数的具体时间,而非自然天数,所以返回的是浮点数类型。但是时间有时也可能是负数,有两种可能,一是时间被设置在了未来,二是程序已经运行了很长时间,但文件刚刚才发生变更,因为Perl在比较时间时用的是程序启动时的变量$^T,所以这种情况也有可能发生
    下面的程序用来说明变量$^T在程序启动时已经设定
    demo12-2:
#!/usr/bin/perl
#证明$^T变量在程序启动后不再改变
print $^T."\n";
print "Press <ENTER> to continue...: ";
$input = <STDIN>;
print "\n$^T\n";
  • 对于-T/B,因为并没有一个标识符可以用来检测文件是文本文件还是二进制文件,所以Perl是根据文件的内容进行猜测——这就意味着结果可能不一定准确。另外,对于一个不存在的文件,二者都返回假。而对于一个空文件,二者都返回真。
  • TTY设备在Linux是一个有历史包袱的文件类型,一般可以被当作键盘一类的交互式设备,-t就用来检查是否是这种设备,对管道和普通文件来说,测试的结果都是false
  • 和其他大多数Perl的操作符一样,当没有指定操作对象时,文件测试操作符也有自己的默认操作对象,那就是$_,但-t是个例外,它默认测试的是STDIN句柄。但如果没有指定操作对象时,Perl解析器会尽力尝试把文件操作符之后的一切字符都理解为操作对象,这有时会引发错误
#文件名保存在$_中
my $series_in_K = -s / 1000; #ERROR HERE!

如果像上面那样想测试文件名保存在$_中的文件大小,并除以1000,就会报错,因为Perl会试着把/理解为操作对象,解决办法是给操作符加上括号(-s),或者更稳妥一点,保证操作符后面跟着正确的操作对象


  1. 对同一个文件进行多次测试可以用逻辑表达式的形式-e $file and -s $file > 100,但这会导致额外的系统开销,因为在执行第二条测试的时候,Perl必须重复一些已经在第一次测试中执行过的I/O操作,众所周知,I/O是导致系统变慢的主要原因,特别是外部I/O。所以Perl提供了虚拟文件句柄_来保存上一次测试过的文件信息,同样的操作就可以写成-e $file and -s _ > 100。虚拟文件句柄保存上一次查询过的文件信息,所以它不受代码块的约束,子程序和循环代码块都可能导致虚拟文件句柄的改变。

Perl 5.10 引入了栈式(stack)文件测试操作,实现对同一个文件进行多次测试,形如-r -w -x -o -d $filename测试文件存在,可读,可写,可执行。靠近文件名的测试会先执行,然后从右往左依次执行。
栈式测试操作在只有布尔值结果的时候比较好用,但如果是返回有实际意义的值可能就会引起误会。比如-s -d $file < 512看起来好像是测试文件存在且大小小于512B,但实际上等价于(-d $file and -s _) < 512:当-d返回假时,后者会用布尔值对应的0来和512比较,得到布尔值“真”


  1. 文件测试操作符并不能测试文件的全部信息,所以Perl移植了Unix系统的stat命令,提供了同名函数stat来测试文件属性信息。stat函数返回一个包含13个元素的列表(如果失败则返回空列表),其中的元素看起来全部由数字填充,stat函数的参数可以是表示文件名的变量也可以是文件句柄。
    demo12-3:
#!/usr/bin/perl
print "please type in filename: ";
chomp($filename = <STDIN>);
my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat $filename;
print "dev:$dev\nino:$ino\nmode:$mode\nnlink:$nlink\nuid:$uid\ngid:$gid\nsize:$size\natime:$atime\nmtime:$mtime\nctime:$ctime\n";
./demo12-3
please type in filename: demo12-3
dev:2
ino:4503599627830863
mode:33279
nlink:1
uid:1000
gid:1000
size:328
atime:1560309963
mtime:1560309963
ctime:1560309963

对应的内容分别如下

元素 含义
dev和ino 文件所在设备的编号和文件的inode编号,决定了文件的唯一性,硬链接创建的文件也有相同的编号
mode 权限位集合
nlink 文件或目录的硬链接数
uid和gid 文件拥有者的用户编号及组id
size 以字节为单位的文件大小(和-s的测试结果相同)
atime、mtime和ctime 三个时间戳,单位为秒
  • 对符号链接调用stat会返回符号链接所指向文件的信息,如果需要查看符号链接本身的信息,需要使用lstat
  • 和文件测试操作符一样,statlstat的默认操作对象是$_

  1. Unix系统中的时间大多以时间戳的形式记录,看起来就是一长串毫无实际意义的数字,实际上代表了Epoch开始之后的秒数或毫秒数,在Unix系统上,Epoch的时间是1970年1月1日00:00:00 UTC。如果要获得可读性更好的结果,可以使用localtime函数对时间戳进行转换。
    localtime函数的参数是代表时间戳的数字,返回则根据上下文的不同有所区别。在标量上下文中,返回的是形如Wed Jun 12 11:36:23 2019这样的字符串,在列表上下文中则返回一组数字元素组成的列表
    demo12-4:
#!/usr/bin/perl
print "Current Time:".localtime $^T."\n";
my ($sec, $min, $hour, $day, $mon, $year, $wday, $yday, $isdat) = localtime $^T;
print "sec:$sec\nmin:$min\nhour:$hour\nday:$day\nmon:$mon\nyear:$year\nwday:$wday\nyday:$yday\nisdat:$isdat\n";
./demo12-4
Current Time:Wed Jun 12 11:39:58 2019sec:58
min:39
hour:11
day:12
mon:5
year:119
wday:3
yday:162
isdat:0

列表中的元素意义如下:

元素 含义
mon 返回0~11的数字,+1代表月份
year 是一个自1900年开始的年数,+1990是实际的年份
wday 返回0(周日)~6(周六),表示在一周内的第几天
yday 表示在今年的第几天,范围从0~364/365(闰年)

另外还有一个函数gmtime它的功能和localtime相似,区别在于它使用的是格林威治时间而不是本地时区。要取得系统当前的时间戳可以使用time函数(例子中的$^T变量在程序启动时设定,不一定代表当前时间),如果没有指定参数,localtimegmtime使用的也是time函数返回的时间戳。


  1. 对于stat函数返回的权限位信息,需要转换成二级制才能理解,Perl提供了一组和C语言一样对二进制按位操作的操作符:
表达式 意义
10 & 12 “按位与”——全1为1,否则为0:1010 & 1100 = 1000(8)
10 | 12 “按位或”——全0为0,否则为1:1010 | 1100 = 1110(14)
10 ^ 12 “按位异或”——相同为0,相反为1:1010 ^ 1100 = 0110(6)
6 << 2 “按位左移”——把符号左边的操作数向左移动,右边补零,移动的位数由右边操作数指定:011000(24)
25 >> 2 “按位右移”——把符号左边的操作数向右移动,越过最低位的舍弃,移动的位数由右边操作数指定:000110(6)
- 10 “按位取反,取决于实际的操作系统的位数,32位系统得0xFFFFFFF5,64位系统得0xFFFFFFFFFFFFFFF5”

按位操作符可以操作位字符串(bitstring)和整数,如果操作数都是整数,则结果也是整数,如果有一个是“位字符串”则结果是位字符串。对于位字符串,"\xAA"(1010 1010) | "\x55"(0101 0101)的结果是"\xFF"(1111 1111)

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,076评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,658评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,732评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,493评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,591评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,598评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,601评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,348评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,797评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,114评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,278评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,953评论 5 339
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,585评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,202评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,442评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,180评论 2 367
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,139评论 2 352

推荐阅读更多精彩内容

  • 写在前面的话 代码中的# > 表示的是输出结果 输入 使用input()函数 用法 注意input函数输出的均是字...
    FlyingLittlePG阅读 2,753评论 0 8
  • 官网 中文版本 好的网站 Content-type: text/htmlBASH Section: User ...
    不排版阅读 4,380评论 0 5
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 5,295评论 0 9
  • 总结了一些开发中常用的函数: usleep() //函数延迟代码执行若干微秒。 unpack() //函数从二进制...
    ADL2022阅读 454评论 0 3
  • PHP常用函数大全 usleep() 函数延迟代码执行若干微秒。 unpack() 函数从二进制字符串对数据进行解...
    上街买菜丶迷倒老太阅读 1,365评论 0 20