我尝试使用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)不同的卷可以有不同的文件系统。
答案 0 :(得分:1)
事实上,每个考虑的目录都必须自行检查。这是因为,在类Unix系统上,任何目录可以是与其他目录不同的文件系统。此外,使用glob
并不十分可靠;来自perlport:
不要指望文件名为globbing。请改用
opendir
,readdir
和closedir
。
但我认为使用-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;
}
}