perl重要的文件系统工具
2013-05-06 16:14:43 阿炯

本站赞助商链接,请多关照。 perl在与文件系统交相时,经常需要加载很多模块,其中好多有用函数分散在各种不同的模块中。它们有些是Perl的内置函数,有些是在同Perl一起发行的标准模块中,另外一些是通过CPAN安装的。

取得当前路径
我经常需要知道当前所在的目录是什么。得到的方法有几种,具体请参考:
perl脚本在运行时取得当前目录

使用临时文件夹

我经常需要创建一批临时文件,并且确保它们在脚本结束的时候会被自动删除。要满足这个需求,最简单的方法是以 CLEANUP 选项使用 File::Temp 模块的 tempdir 函数来创建一个临时文件夹。
use autodie;
use File::Temp qw(tempdir);

my $dir = tempdir( CLEANUP => 1 );
print "$dir\n";

open my $fh, '>', "$dir/some_file.txt";
print $fh "text";
close $fh;

与操作系统无关的路径
如果上面的代码要在 Linux 和 Windows 上都要运行,人们会习惯在 Windows 平台上用反斜线分割路径,同理在VMS上不能执行。而这就是 File::Spec::Functions模块中catfile函数的用武之地。
use File::Spec::Functions qw(catfile);
use File::Temp qw(tempdir);

my $dir = tempdir( CLEANUP => 1 );
print "$dir\n";
print catfile($dir, 'some_file.txt'), "\n";

执行这个代码后,能看到临时文件夹被打印出来,紧跟其后的是文件名字。

切换目录
通常情况下,先切换工作目录到临时文件夹再进行操作会更简单。但是也存在其他情况的写测试,此时我们可以使用内置函数'chdir'。
use autodie;
use File::Temp qw(tempdir);
use Cwd;

my $dir = tempdir( CLEANUP => 1 );
print cwd, "\n";
chdir $dir;
print cwd, "\n";

open my $fh, '>', 'temp.txt';
print $fh 'text';
close $fh;

以上看起来可以正常工作,但是当File::Temp尝试删除文件夹,而我们仍然"在里面"(之前切换工作目录到它)时就会有问题。

例如,我会得到下面的错误信息:
cannot remove path when cwd is /tmp/V18dy7nB2r for /tmp/V18dy7nB2r:  at /usr/share/perl/5.10/File/Temp.pm line 902.
GLOB(0x955f968)text

为了避免这种情况,我通常会在切换目录之前保存cwd的返回值,并且在最后再次调用chdir。
my $original = cwd;
 ...
chdir $original;

这样仍然会有个小问题。如果我在脚本中间调用exit(),或者在执行到'chdir $original'之前抛出异常而终止脚本,会发生什么?

Perl提供了一个解决方案:把最后一个chdir包裹在END块中。如此,就会确保无论何时、以何种方式退出脚本,这些代码都会执行到。
my $original = cwd;
...
END {
 chdir $original;
}

相对路径
当写一个多文件构成的项目(例如一个或多个脚本,多个模块,也可能是多个模板),并且我不想安装它们时,最好的目录组织方式是:确保每个文件都在一个固定的相对位置。

所以,我的项目目录通常会包含一个脚本子文件夹,一个模块文件夹(lib), 一个模板文件夹, 等等:

project/
 scripts/
 lib/
 templates/

那么,如何才能确保脚本能够找到模板? 有好几个处理办法:
use strict;
use warnings;
use autodie;
use FindBin qw($Bin);
use File::Basename qw(dirname);
use File::Spec::Functions qw(catdir);

print $Bin, "\n"; # /home/freeoa/mysite/scripts
print dirname($Bin), "\n"; # /home/freeoa/mysite
print catdir(dirname($Bin), 'templates'), "\n"; # /home/freeoa/mysite/templates

FindBin模块导出的参量$bin存放着当前脚本的目录路径,在我们的例子中就是指向project/scripts/文件夹的路径。

File::Basename中的dirname函数会传入一个路径,并返回除最后一部分之外的路径。

最后一行File::Spec::Functions模块的catdir函数基本上和我们之前看到的catfile一样。除了打印到屏幕上,当然也可以使用catdir的返回值来表示templates路径。

从相对路径中加载模块

大部分情况下,要查找和加载的模块都会在项目的lib/文件夹中。为此,我们会把之前的代码和lib指令连用。这样会改变@INC变量的值,把相对路径添加在数组开头。
use strict;
use warnings;
use autodie;
use FindBin qw($Bin);
use File::Basename qw(dirname);
use File::Spec::Functions qw(catdir);
use lib catdir(dirname($Bin), 'lib');
use Rocket::Launcher;

这里假定存在lib/Rocket/Launcher.pm文件。


参考来源:Perl5中最重要的文件系统工具