Perl小技巧:文件操作

当前位置:首页>Perl>perl技巧>Perl小技巧:文件操作

Perl小技巧:文件操作

时间:2015-06-06 15:28来源:网络整理 作者:KKWL 点击:
opendirDIR,$path;@arr1=readdirDIR;@arr2=grep{-T"$path$_"}@arr1;#textfilesonly@arr3=grep{!-d"$path$_"}@arr1;#nodirectories@arr4=grep{-s"$path$_"1024}@arr1;#lessthan1K代码解释:假如被测试的目录项是一个文本文件,那么-T文

opendirDIR,$path;@arr1=readdirDIR;@arr2=grep{-T"$path$_"}@arr1;#textfilesonly@arr3=grep{!-d"$path$_"}@arr1;#nodirectories@arr4=grep{-s"$path$_"<1024}@arr1;#lessthan1K代码解释:假如被测试的目录项是一个文本文件,那么-T文件操作符就会返回真。其实针对目录项的测试操作还有很多。(注:文件和目录在系统中都是以目录项的形式来管理的,所以要区别一个目录项指向的是一个文件还是一个目录需要相应的操作符)。注意上面的readdir函数返回指定目录下的所有目录项。因为在grep函数中对目录项的测试需要文件的完全路径,所以我们把$PATH(存储了目录项的部分路径)和$_(存储了目录项的名字)中的内容联合起来得到文件的完全路径*对目录进行递归搜索*useFile::Find;find(\&handleFind,'imac:documents:code');subhandleFind{my$foundFile=$File::Find::name;PRint"$foundFile\n"if($foundFile=~/\.html?$/i);}RESULT:imac:documents:code:index.htmlimac:documents:code:perl:example.HTM运行结果:代码讨论:那些工作于Unix系统的Perl程序员可以非常简便的利用UNIX上提供的工具来完成许多日常的工作,比如递归的列出指定目录下的所有目录项(也就是列出指定目录及指定目录子目录下的所有目录项目)。然而Perl的一个最大的特征就是可以运行于很多的平台上。所以如果你碰巧工作在一个非UNIX的平台,或者如果你虽工作在UNIX平台,但不喜欢使用系统工具写脚本,你可以选择Perl。要完成这些巧妙的工作,你需要使用perl中的File:Find模块。当你加载了这个模块的时候,你就可以使用其中的find子函数,在调用这个函数的时候,需要带参数:第一个参数是一个函数的引用,这个函数由你自己建立,每次一个文件被找到的时候,它都会运行。接下来的一个参数是一串你想要搜索的路径。我写的这个示例脚本是运行在MacintoshOS8.x系统上的,所以我使用了Mac系统的路径分隔符:。如果是在Windows,你可以用反斜杠,如果是在Unix系统则是正斜杠(至于在Amiga系统上用什么我就不知道了)。总之,find函数将会在每次找到一个文件的时候调用你给出的子函数,而且会对子目录进行查找。在我的handledfind子函数中,我通过这个模块特定变量$File::Find::name来获得每次find找到的文件名。然后,就可以对该文件执行任何你想的测试,在上面的例子中,我们输出有.html的扩展名文件名。*文件读操作**一次读入整个文件内容。*openFH,"<anthem";$/=undef;$slurp=;print$slurp;运行结果:一下就显示了所有的文件内容,此刻你应该非常的自豪。:)代码讨论:尖括号<>对文件句柄进行操作,在标量上下文中它将返回文件的下一条记录,在数组上下文中它将返回所有的记录。在默认的情况下,文件中的记录被认为是由换行符分开(例如回车或其他代表新行开始的字符)。你可以重新设定这个默认的分隔符,然后Perl将会以你指定的分隔符为准来替代换行符。全局变量$/里存储了输入文件的分隔符,如果你把$/的值设置为undef,那么Perl将会认为整个文件是一条记录(因为此刻已经没有文件分隔符了)。牢记$/是全局变量,千万不要在脚本的其他地方不经意的改变它,这个错误将很难被发现。你可能会问,我们能否不改变$/,而采用把文件的所有记录读到一个数组中,然后把数组联合成一个很长的字符串(比如$slurp=join("",);)的方法实现一次读入文件。当然这也是一个有效的解决办法,但是你会发现它很慢,是否选用它取决你的应用,取决于你是否关心运行速度。*赋值**把一个文件句柄赋给另一个文件句柄*open(MYOUT,">bottle.txt");*STDOUT=*MYOUT;print"message";运行结果:文本文件bottle.txt现在包含message字符串。代码讨论:以前可能你配合使用过Print函数和文件句柄,但是你是否知道就算你没有使用文件句柄,Perl也默认你在使用一个称为STDOUT的句柄?C程序员知道STDOUT代表标准输出,也就是通常的屏幕,或终端窗口(或者是CGI程序的输出端-浏览器)。在这里我们完成的工作是创建我们自己的文件句柄,它指向一个给定的文件,然后我们做了一件比较鬼的工作,使用*前缀把STDOUT转换为typeglob类型。Typeglob类型的数据可以有别名,这样一个变量可能会指向另一个其他名字的变量。上面第二行代码使STDOUT指向MYOUT变量。所以执行print操作时的默认输出对象也就成为了我们创建的文件句柄。*同时向两个文件句柄执行写操作*useIO::Tee;$tee=IO::Tee->new(">>debuglog.txt",\*STDOUT);print$tee"anerrorocurredon".scalar(localtime)."\n";运行结果:anerrorocurredonFriFeb2321:44:202001代码讨论:如果,由于种种原因你想要同时向两个位置写入同一个字符串,这和UNIX下的tee工具的用途一样。即使你不是工作在Unix平台上,Perl也通过Tee模块为你提供这个功能。Tee模块可以在CPAN下载,你应该把它安装到Perl的IO库文件夹中。Tee模块以OOP方式编写,所以使用它之前你应该首先使用它的new方法来创建一个Tee对象,整个过程需要两个参数,每个参数既可以是代表文件句柄的字符串,也可以是一个对已打开的文件句柄的引用。在上面的例子中,我们用一个字符串来代表一个以附加模式打开的文件句柄,它指向名为debuglog.txt的文件,另一个参数是系统内置的文件句柄STDOUT,整个句柄是系统自动创建的,print函数默认情况对它进行操作。为了得到一个文件句柄的引用我们需要对一个typeglob类型的数据使用反斜杠。Typeglob可以代表任何已命名的某个变量,不论它是数组,散列还是标量等。使用*很有必要,因为文件句柄自己没有前缀符号。new操作符返回Tee类的一个实例对象,然后我们把整个实例赋给$tee标量。现在,无论什么时候我们向$tee进行写入操作,我们都同时向两个位置进行写操作。*更多文件操作。。。**从一个文件的完全路径中找出它的名字*useFile::Basename;$path="/docs/sitecircus.com/html/tricks/trick.of.the.week.html";$basename=basename($path,".html");print$basename;运行结果:trick.of.the.week代码讨论:好了,成功了。问题是要找出文件的名字,要不带任何路径前缀,不带任何扩展名。File::Basename模块可以使这很容易实现,我们只需要把文件的完全路径还有要剔除的扩展名传给它。上面的path变量是文件的完全路径,注意文件分隔符是/,这个字符很特殊,因为它是操作系统的保留字符。这里你不能在文件名里使用系统的分隔符。你应该知道当今流行的操作系统都使用自己独特的文件分隔符:Unix使用/,Windows使用\,Macintosh使用:(顺便说一下,在Windows上的Perl脚本中,你既可以使用\也可以使用/作为文件分隔符,Perl的解释器能理解你的意思)。File::Basename,当然,能正确在完全路径中找到文件名,不论时在什么系统下。*改变文件的所有者*($uid,$gid)=(getpwnam($username))[2,3]ordie"$usernotinpasswdfile";chown($uid,$gid,$file)orwarn"couldn'tchown$file.";运行结果:无输出代码讨论:有的时候,你可能知道一个用户名,而你想用这个用户名做些事,比如改变一个文件的所有者。但是不幸的是,Perl的chown命令不能接受用户名作为参数,但是可以接受一对数字:userid和groupid。虽然有这些不便之处,Perl并没有让我们陷入困境,我们可以把用户名作为getpwnam函数的参数,获得一个数组,里面包含了用户名对应的userid和groupid,分别对应着数组里的第二和第三个元素。

------分隔线----------------------------