如何在 Perl 中找到文件的大小写保留名称?
How do I find the case-preserved name of a file in Perl?
在不区分大小写的文件系统(例如 NTFS 或 HFS+)上,给定一个文件名,确定文件名的大小写保留版本的最有效方法是什么?
考虑 HFS+ (Mac OS X):
> perl -E 'say "yes" if -e "/TMP"'
yes
它说它当然存在,但我不知道它的外壳是如何保存的。确定实际情况的最有效方法是什么?
到目前为止我尝试过的:
glob
with character 类: 它不适用于 Windows:
> perl -E "say for glob "C:\Perl"
C:\Perl
> perl -E "say for glob "C:\[Pp][Ee][Rr][Ll]"
请注意最后一条命令没有输出。 :-(
opendir
/readdir
:有效,但读取整个目录似乎效率很低:
> perl -E "opendir my $dh, 'C:\'; say for grep { lc $_ eq 'perl' } readdir $dh; close $dh"
Perl
认为应该有一些核心操作系统指令或其他东西来更有效地获取这些信息是不是很疯狂?
glob
函数无法识别正则表达式样式字符 类 ([Pp], [Ee])
。相反,它使用 csh
风格的通配符扩展。要完成您的示例任务,您需要使用语法
glob("C:\{P,p}{E,e}{R,r}{L,l}")
我不知道 glob
的实现细节,但它似乎还需要检查目录中的每个文件,并且不一定比你的 readdir/grep
更有效成语.
或者更简洁(同样,不一定更有效),glob/grep
成语:
perl -E "say for grep {/C:\PERL/i} glob('C:\*')"
(已更新,仍未测试)
在 Windows、
>perl -MWin32 -E"say Win32::GetLongPathName($ARGV[0])" "C:\PROGRAM FILES"
C:\Program Files
>perl -MWin32 -E"say Win32::GetLongPathName($ARGV[0])" C:\PROGRA~1
C:\Program Files
在 unix 上,fcntl
的 F_GETPATH
函数就可以了。
opendir
/readdir
/grep
解决方案是正确的。 Via Twitter, Neil Bowers points to this quotation from perlport:
Don't count on filename globbing. Use opendir
, readdir
, and closedir
instead.
@miyagawa, also via Twitter,表示没有系统调用,如果有,也不能移植。
并且考虑到 @mob's answer and comments from David Golden 建议 glob
会比 opendir
、readdir
更贵,无论如何,似乎没有其他办法。
下面是我编写的用于查找目录中给定基本名称的所有案例的函数:
sub _actual_filenames {
my $dir = shift;
my $fn = lc shift;
opendir my $dh, $dir or return;
return map { File::Spec->catdir($dir, $_) }
grep { lc $_ eq $fn } readdir $dh;
}
在不区分大小写的文件系统(例如 NTFS 或 HFS+)上,给定一个文件名,确定文件名的大小写保留版本的最有效方法是什么?
考虑 HFS+ (Mac OS X):
> perl -E 'say "yes" if -e "/TMP"'
yes
它说它当然存在,但我不知道它的外壳是如何保存的。确定实际情况的最有效方法是什么?
到目前为止我尝试过的:
glob
with character 类: 它不适用于 Windows:> perl -E "say for glob "C:\Perl" C:\Perl > perl -E "say for glob "C:\[Pp][Ee][Rr][Ll]"
请注意最后一条命令没有输出。 :-(
opendir
/readdir
:有效,但读取整个目录似乎效率很低:> perl -E "opendir my $dh, 'C:\'; say for grep { lc $_ eq 'perl' } readdir $dh; close $dh" Perl
认为应该有一些核心操作系统指令或其他东西来更有效地获取这些信息是不是很疯狂?
glob
函数无法识别正则表达式样式字符 类 ([Pp], [Ee])
。相反,它使用 csh
风格的通配符扩展。要完成您的示例任务,您需要使用语法
glob("C:\{P,p}{E,e}{R,r}{L,l}")
我不知道 glob
的实现细节,但它似乎还需要检查目录中的每个文件,并且不一定比你的 readdir/grep
更有效成语.
或者更简洁(同样,不一定更有效),glob/grep
成语:
perl -E "say for grep {/C:\PERL/i} glob('C:\*')"
(已更新,仍未测试)
在 Windows、
>perl -MWin32 -E"say Win32::GetLongPathName($ARGV[0])" "C:\PROGRAM FILES"
C:\Program Files
>perl -MWin32 -E"say Win32::GetLongPathName($ARGV[0])" C:\PROGRA~1
C:\Program Files
在 unix 上,fcntl
的 F_GETPATH
函数就可以了。
opendir
/readdir
/grep
解决方案是正确的。 Via Twitter, Neil Bowers points to this quotation from perlport:
Don't count on filename globbing. Use
opendir
,readdir
, andclosedir
instead.
@miyagawa, also via Twitter,表示没有系统调用,如果有,也不能移植。
并且考虑到 @mob's answer and comments from David Golden 建议 glob
会比 opendir
、readdir
更贵,无论如何,似乎没有其他办法。
下面是我编写的用于查找目录中给定基本名称的所有案例的函数:
sub _actual_filenames {
my $dir = shift;
my $fn = lc shift;
opendir my $dh, $dir or return;
return map { File::Spec->catdir($dir, $_) }
grep { lc $_ eq $fn } readdir $dh;
}