You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl实现目录-文件哈希数组时无法识别子目录的问题求助

Perl实现目录-文件哈希数组时无法识别子目录的问题求助

问题描述

我想要实现这样的功能:遍历当前目录下的所有子目录,为每个目录创建一个数组存储该目录及其所有子目录下的文件,最后把这些数组存入一个哈希(键是目录名,值是对应文件数组)。我写了一段Perl代码,虽然能列出目录里的文件,但无法识别子目录——明明有些目录里有子目录,代码里判断-d $file的语句却从来不会输出。我也试过用glob处理子目录,但效果不理想,麻烦大家帮我看看代码哪里出问题了?

附上我写的代码:

#!/usr/bin/perl -w

use strict;
use warnings;
use Data::Dumper qw(Dumper);
use File::Basename;

my %hash;
my @store;
my @list_of_dirs = grep { -d } glob "*";

print "LIST of DIRs = @list_of_dirs \n";

foreach my $dir (@list_of_dirs) {
    opendir(DIR, $dir) or die $!;
    while (my $file = readdir(DIR)) {
        next if ($file =~ m/^\./);
        print "FILE = $file\n";
        if ( -d $file) { print "IT IS A DIRECTORY\n"; }
        ## 这句从来不会打印,哪怕目录里确实有子目录
        push(@store, $file);
    } #end_of_while
    print "$dir = @store \n";
    $hash{"$dir"} = [@store];
    @store = ();
} #end_of_foreach

print Dumper \%hash;

我还试过这段处理子目录的代码,但也没达到预期:

while ( my $subdir = glob "$file/*" ) {
    my @sub_files = grep -f, glob "$subdir/*";
    print "SUBDIR $dir = @sub_files\n";
}

问题根源

你代码里判断子目录的逻辑有个关键错误:当你用readdir读取$dir目录下的内容时,得到的$file只是文件名/子目录名,不是完整路径。这时候用-d $file判断的是当前工作目录下是否存在这个目录,而不是$dir目录下的子目录,自然判断失败了。

举个例子:假设你当前目录有个docs目录,里面有个images子目录。当遍历docs时,readdir得到的$file是images,这时候-d images检查的是当前目录下有没有images,而不是docs/images,所以返回false,不会打印那句提示。


修正方案

我们需要把$dir和$file拼接成完整路径,再进行文件类型判断。另外,为了递归遍历所有子目录里的文件,最好写一个递归函数来处理,这样不管嵌套多少层子目录都能覆盖到。

下面是修正后的完整代码:

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper qw(Dumper);
use File::Spec; # 用来安全拼接路径,跨平台兼容

my %dir_files_hash;

# 获取当前目录下的所有子目录
my @list_of_dirs = grep { -d } glob "*";

# 遍历每个目录,收集所有文件(包括子目录里的)
foreach my $dir (@list_of_dirs) {
    my @all_files = ();
    collect_files($dir, \@all_files);
    $dir_files_hash{$dir} = \@all_files;
    print "$dir 下的文件列表:@all_files\n";
}

print "\n最终的哈希结构:\n", Dumper(\%dir_files_hash);

# 递归收集目录下的所有文件
sub collect_files {
    my ($current_dir, $files_ref) = @_;
    
    opendir(my $dh, $current_dir) or die "无法打开目录 $current_dir: $!";
    while (my $entry = readdir($dh)) {
        next if $entry =~ /^\./; # 跳过隐藏文件和.、..
        
        # 拼接完整路径
        my $full_path = File::Spec->catfile($current_dir, $entry);
        
        if (-d $full_path) {
            # 如果是子目录,递归遍历它
            collect_files($full_path, $files_ref);
        } else {
            # 如果是文件,添加到数组里
            push @$files_ref, $entry; # 如果你需要完整路径,就push $full_path
        }
    }
    closedir($dh);
}

关键修改点说明

  1. 使用完整路径判断:用File::Spec->catfile拼接目录和文件名,确保路径跨平台兼容,判断-d $full_path就能正确识别子目录了。
  2. 递归函数遍历子目录:写了collect_files递归函数,遇到子目录就深入进去,把里面的文件也收集到当前目录的数组里,完全满足你的需求。
  3. 代码更规范:用my $dh这种词法句柄代替全局的DIR,避免潜在的句柄冲突;去掉了不必要的-w(因为已经用use warnings了)。

如果你需要在数组里存储完整文件路径而不是只存文件名,只需要把push @$files_ref, $entry;改成push @$files_ref, $full_path;就行。


备注:内容来源于stack exchange,提问作者nandeesh v

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.22 07:44:33