如何在Perl中检测不区分大小写的文件系统?

时间:2015-02-19 00:56:34

标签: perl filesystems case-sensitive

我尝试使用File::Spec->case_tolerant,但它在HFS +上返回false,这是错误的。我怀疑是因为File::Spec::Unix总是返回false。我目前的解决方法是这个功能:

my $IS_CASE_INSENSITIVE;
sub _is_case_insensitive {
    unless (defined $IS_CASE_INSENSITIVE) {
        $IS_CASE_INSENSITIVE = 0;
        my ($uc) = glob uc __FILE__;
        if ($uc) {
            my ($lc) = glob lc __FILE__;
            $IS_CASE_INSENSITIVE = 1 if $lc;
        }
    }
    return $IS_CASE_INSENSITIVE;
}

但是,这是一个黑客攻击:1)在区分大小写的文件系统上,这两个文件可能都存在; 2)不同的卷可以有不同的文件系统。

2 个答案:

答案 0 :(得分:1)

事实上,每个考虑的目录都必须自行检查。这是因为,在类Unix系统上,任何目录可以是与其他目录不同的文件系统。此外,使用glob并不十分可靠;来自perlport

  

不要指望文件名为globbing。请改用opendirreaddirclosedir

但我认为使用-e@borodin正在使用{{3}}。所以这是一个使用-e来确定指定目录是否在不区分大小写的文件系统上的函数:

my %IS_CASE_INSENSITIVE;
sub is_case_insensitive {
    my $dir = shift;
    unless (defined $IS_CASE_INSENSITIVE{$dir}) {
        $IS_CASE_INSENSITIVE{$dir} = -e uc $dir && -e lc $dir;
    }
    return $IS_CASE_INSENSITIVE{$dir};
}

您可以为Windows添加一些启发式方法来缓存驱动器号的值,因为它定义了一个挂载点。当然,如果目录的大写和小写变体都存在,它将在case-sensisitve文件系统上失败。但除此之外,除非有其他方法告诉更多全局哪些目录与哪个挂载点匹配,否则您必须检查任何目录。

答案 1 :(得分:0)

我建议您使用核心File::Temp模块来创建一个名称中包含小写字符的新唯一文件。当对象被销毁时,该文件被设置为删除,即子例程在不存在之前退出的时间。

如果在通过大写文件名访问时文件不存在,则文件系统区分大小写

如果大写的名称​​确实存在,那么我们必须检查我们的大写版本已经存在的文件没有发生,所以我们删除了该文件。如果大写条目现已消失,则归档系统不区分大小写

如果上层名称仍然存在,则它是我们在创建临时文件之前存在的文件。我们只是循环并创建一个具有不同名称的新临时文件,尽管这种情况发生的可能性非常小。如果您愿意,可以通过使用SUFFIX的古怪值来进一步降低这种可能性。请注意,您使用的字符在您要测试的任何文件系统上都有效。

我在Windows 7和Ubuntu上都测试了这个。

use strict;
use warnings;
use 5.010;
use autodie;

use File::Temp ();

printf "File system %s case_insensitive\n", case_insensitive() ? "is" : "isn't";


sub case_insensitive {

  while () {

    my $tmp = File::Temp->new(
      TEMPLATE => 'tempXXXXXX',
      SUFFIX   => '.tmp',
      UNLINK   => 1,
    );

    my $uc_filename = uc $tmp->filename;

    return 0 if not -e $uc_filename;
    $tmp = undef;
    return 1 if not -e $uc_filename;
  }
}