Как читать каталоги и подкаталоги, не зная имени каталога в perl?
Привет я хочу читать каталоги и подкаталоги, не зная имени каталога. Текущий каталог-это "D:/Temp". 'Temp' имеет подкаталоги типа 'A1','A2'. Опять же 'A1' имеет подкаталоги типа 'B1','B2'. Опять же 'B1' имеет подкаталоги типа 'C1','C2'. Perl script не знает этих каталогов. Поэтому он должен сначала найти каталог, а затем прочитать один файл за раз в dir 'C1', как только все файлы будут прочитаны в 'C1', он должен измениться на dir 'C2'. Я пробовал с кодом ниже здесь я не хочу читать все файлы в массиве (@files), но нужен один файл одновременно. В массиве @dir элементы должны быть в виде паров.
$dir[0] = "D:/Temp/A1/B1/C1"
$dir[1] = "D:/Temp/A1/B1/C2"
$dir[2] = "D:/Temp/A1/B2/C1"
Ниже приведен код, который я пробовал.
use strict;
use File::Find::Rule;
use Data::Dumper;
my $dir = "D:/Temp";
my @dir = File::Find::Rule->directory->in($dir);
print Dumper (@dir);
my $readDir = $dir[3];
opendir ( DIR, $readDir ) || die "Error in opening dir $readDirn";
my @files = grep { !/^..?$/ } readdir DIR;
print STDERR "files: @files nn";
for my $fil (@files) {
open (F, "<$fil");
read (F, my $data);
close (F);
print "$data";
}
5 ответов:
Ваша цель: найти абсолютные пути к тем каталогам, которые сами по себе не имеют дочерних каталогов.
Я буду называть эти каталоги интересующими терминальными каталогами. Вот прототип функции, которая, как я полагаю, обеспечивает удобство, которое вы ищете. Функция возвращает свой результат в виде списка.
my @list = find_terminal_directories($full_or_partial_path);И вот реализация
find_terminal_directories(). Обратите внимание, что эта реализация не требует использования любого глобального переменные . Также обратите внимание на использование частной вспомогательной функции, которая называется рекурсивно.В моей системе Windows 7, для входного каталога C:/Perl/lib/Test , я получаю вывод:
== List of Terminal Folders == c:/Perl/lib/Test/Builder/IO c:/Perl/lib/Test/Builder/Tester c:/Perl/lib/Test/Perl/Critic == List of Files in each Terminal Folder: == c:/Perl/lib/Test/Builder/IO/Scalar.pm c:/Perl/lib/Test/Builder/Tester/Color.pm c:/Perl/lib/Test/Perl/Critic/Policy.pmРеализация
#!/usr/bin/env perl use strict; use warnings; use Cwd qw(abs_path getcwd); my @dir_list = find_terminal_directories("C:/Perl/lib/Test"); print "== List of Terminal Directories ==\n"; print join("\n", @dir_list), "\n"; print "\n== List of Files in each Terminal Directory: ==\n"; for my $dir (@dir_list) { for my $file (<"$dir/*">) { print "$file\n"; open my $fh, '<', $file or die $!; my $data = <$fh>; # slurp entire file contents into $data close $fh; # Now, do something with $data ! } } sub find_terminal_directories { my $rootdir = shift; my @wanted; my $cwd = getcwd(); chdir $rootdir; find_terminal_directories_helper(".", \@wanted); chdir $cwd; return @wanted; } sub find_terminal_directories_helper { my ($dir, $wanted) = @_; return if ! -d $dir; opendir(my $dh, $dir) or die "open directory error!"; my $count = 0; foreach my $child (readdir($dh)) { my $abs_child = abs_path($child); next if (! -d $child || $child eq "." || $child eq ".."); ++$count; chdir $child; find_terminal_directories_helper($abs_child, $wanted); # recursion! chdir ".."; } push @$wanted, abs_path($dir) if ! $count; # no sub-directories found! }
use File::Find; use strict; use warnings; my @dirs; my %has_children; find(sub { if (-d) { push @dirs, $File::Find::name; $has_children{$File::Find::dir} = 1; } }, 'D:/Temp'); my @ends = grep {! $has_children{$_}} @dirs; print "$_\n" for (@ends);
Возможно, будет полезно следующее:
use strict; use warnings; use File::Find::Rule; my $dir = "D:/Temp"; local $/; my @dirs = sort File::Find::Rule->exec( sub { File::Find::Rule->directory->in($_) == 1 } )->directory->in($dir); for my $dir (@dirs) { for my $file (<"$dir/*">) { open my $fh, '<', $file or die $!; my $data = <$fh>; close $fh; print $data; } }
local $/;позволяет нам слить содержимое файла в переменную. Удалите его, если вы хотите прочитать только первую строку.subвexec()используется для передачи только тех dir, которые не содержат dirsortиспользуется для упорядочивания этих дир в нужном вам порядке- файл Глоб
<"$dir/*">используется для получения файлов в каждом dirEdit : модифицировали код для поиска только " каталоги терминалов."Спасибо DavidRR за это уточнение спецификации.
Я бы использовал
File::FindПример сценария:
#!/usr/bin/perl use strict; use warnings; use File::Find; my $dir = "/home/chris"; find(\&wanted, $dir); sub wanted { print "dir: $File::Find::dir\n"; print "file in dir: $_\n"; print "complete path to file: $File::Find::name\n"; }Выходы:
$ test.pl dir: /home/chris/test_dir file in dir: test_dir2 complete path to file: /home/chris/test_dir/test_dir2 dir: /home/chris/test_dir/test_dir2 file in dir: foo.txt complete path to file: /home/chris/test_dir/test_dir2/foo.txt ...
Comments