Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: разработка для Web > прочитать вложенные директории


Автор: murka 31.7.2006, 15:34
 smile Нужна помощь!
Читаю директорию и делаю определенные действия над каждым из её объектов. Вложенность неопределена, нужно просмотреть все файлы во всех папках. Запуталась! 
Как определять папка это или файл и читать директорию могу, а вот как идти дальше во вложенные директории и вернуться обратно - не пойму! 
Может кто чего подскажет! 

Автор: Nab 31.7.2006, 16:54
Выделить в отдельную функцию, и вызывать рекурсивно...
Можно с заходом в каждую директорию, можно по полному пути .... выбирайте как удобней... 

Автор: korob2001 31.7.2006, 17:16
Вот написал пример, без рекурсии и сторонних модулей. Подробности смотри в комнтариях.

Файл: scan.pl
Код

#!/usr/bin/perl
use strict;

# Получаем имя файла из массива @ARGV
my @dir_list = (shift);

# Если полученный файл существует и является каталогом, то:
if (-e $dir_list[0] and -d $dir_list[0]) {

    # Открываем файл, сюда будем сохранять имена всех вложенных файлов,
    # вместе с путями.
    open my $fh, ">", "all_files.txt" or die "Can't open file: $!\n";

    # Извлекаем первый елемент из массива на каждой итерации цикла
    # до тех пор, пока массив не будет пуст.
    while (my $dir = shift @dir_list) {

           # Открываем полученный каталог
           opendir(DIR, $dir) or die "Can't open directory '$dir': $!\n";

                   # Читаем каталог в цикле
                   while (my $file = readdir DIR) {

                          # Отбрасываем имена текущего и родительского каталогов
                          next if $file =~ /^\.\.?$/;

                          # Если это каталог, то:
                          if ( -d "$dir/$file" ) {
                                # добавляем его в массив @dir_list
                                unshift @dir_list, join("/", $dir, $file);
                          } else {
                                # в противном случае
                                print $fh "$dir/$file\n";
                          }
                   }

           # Закрываем текущий каталог
           closedir(DIR);

    }

    # Закрываем наш файл
    close($fh) or die "Can't close file: $!\n";
}

Запускаешь из командной строки, например вот так:
perl scan.pl C:/WINDOWS

Врезультате, в том же каталоге, где находится сам файл scan.pl будет создан текстовый файл all_file.txt, в котором будет сохранён список всех вложенных файлов в указанном каталоге, а также и вложенных каталогах.

ЗЫ: Код было бы не плохо ещё немного доработать, а так же сократить. Я специально использовал длиные записи, например вот это условие:
Код

# Если это каталог, то:
if ( -d "$dir/$file" ) {
    # добавляем его в массив @dir_list
    unshift @dir_list, join("/", $dir, $file);
} else {
    # в противном случае
    print $fh "$dir/$file\n";
}

можно было бы записать и вот так:
Код

(-d "$dir/$file") ? unshift @dir_list, join("/", $dir, $file) : print $fh "$dir/$file\n";

С другой стороны, в этом же условии записывать в файл, только в том случае, если он действительно является файлом, а не чем нить ещё. Потому else можно заменить на elsif(условие), если это конечно нужно. 

Автор: korob2001 31.7.2006, 18:50
Вот аналогичный пример с рекурсией:
Код

#!/usr/bin/perl
use strict;

my $fh;
my @dir_list = (shift);

if (-e $dir_list[0] and -d $dir_list[0]) {
    open $fh, ">", "all_filez.txt" or die "Can't open file: $!\n";
    scan_dir(\@dir_list); # ВЫЗЫВАЕМ РЕКУРСИВНЫЙ МЕТОД (ПОДПРОГРАММУ)
    close($fh) or die "Can't close file: $!\n";
}

sub scan_dir {
    my $dir  = shift @{$_[0]} || return;
    opendir(DIR, $dir) or die "Can't open directory '$dir': $!\n";
    while (my $file = readdir DIR) {
       next if $file =~ /^\.\.?$/;
       (-d "$dir/$file") ? unshift(@{$_[0]},join("/",$dir,$file)) : print $fh "$dir/$file\n";
    }
    closedir(DIR);
    scan_dir($_[0]); # ВЫЗЫВАЕМ САМИ СЕБЯ
}

Программа намного меньше, но с примером без рекурсии можно сделать тоже самое. 

Автор: Nab 31.7.2006, 19:21
Мне метод без рекурсии очень понравился, хотя запись в файл в качестве примера не годиться, лучше построить хеш...

А вот второй пример, мне не очень smile . От предыдущего оличается мало, хотя и использует рекурсию...
Я его немного переделаю...

Код

#!/usr/bin/perl    
use strict;    

scan_dir(shift); # ВЫЗЫВАЕМ РЕКУРСИВНЫЙ МЕТОД (ПОДПРОГРАММУ)    

sub scan_dir {    
    my $dir  = shift;    
    opendir(DIR, $dir) or die "Can't open directory '$dir': $!\n";    
    while (my $file = readdir DIR) {    
       next if $file =~ /^\.\.?$/; # пропускаем если двоеточие
       if (-d "$dir/$file") {
            scan_dir("$dir/$file") # если находим поддиректорию, то вызываем себя же, но для этого каталога.
        } else {
            print "$file\tin $dir\n"; # Вот здесь можем сделать что нибудь с файлом
        }    
    }    
    closedir(DIR);    
}

1;


В лучших традициях допишу smile
Вот эта конструкция:
Код

       if (-d "$dir/$file") {
            scan_dir("$dir/$file") # если находим поддиректорию, то вызываем себя же, но для этого каталога.
        } else {
            print "$file\tin $dir\n"; # Вот здесь можем сделать что нибудь с файлом
        }    

может быть заменена на :
Код

(-d "$dir/$file")?scan_dir("$dir/$file"):print "$file\tin $dir\n";

Но как по мне развернутая форма выигрывает в читабельности  smile   

Автор: korob2001 1.8.2006, 01:07
Цитата(Nab @  31.7.2006,  16:21 Найти цитируемый пост)
Но как по мне развернутая форма выигрывает в читабельности

Я не спорю, просто некоторые товарисчи предпочитают писать компактно, желательно вообще в одну строку.  smile 
 

Автор: Nab 1.8.2006, 01:21
Цитата(korob2001 @ 1.8.2006,  01:07)
Цитата(Nab @  31.7.2006,  16:21 Найти цитируемый пост)
Но как по мне развернутая форма выигрывает в читабельности

Я не спорю, просто некоторые товарисчи предпочитают писать компактно, желательно вообще в одну строку.  smile

Не спорю, но мы же не ПерлГольф играем, а помогаем народу понять как оно работает smile

А если у человека, в особенности у начинающего, вопрос, а он видит ТАКОЕ, что даже прочитать не может, то кому такая помощь нужна? И так все знают кто здесь модер smile

А те, кто предпочитают писать в одну строчку, обычно задают очень нетривиальные вопросы и знают чего хотят добиться в результате smile 

Автор: aksined 2.8.2006, 08:55
Если вы хотите помочь человеку с обработкой всех файлов, то хотя бы расскажите, как это сделать с помощью модуля, который входит в стандартную поставку. Ставить не надо, а использовать несложно.
Для вас написать несколько красивых решений - это одно. А человек потом все рвно вряд ли будет оформлять функции в виде модуля. Будет их копировать из скрипта в скрипт.
Код

use File::Find;
my $Dir = "с:/dir";
my @Subdir = qw(aaa bbb ccc);#новые подкаталоги добавлять сюда
find (\&search, map {"$DirCert/$_"} @Subdir);
#========================
sub search{
  my $name = $File::Find::name;
  if(-d $name){
    print "$name - это каталожица\n";
  }
  elsif(-f $name){
    print "$name - это файл\n";
  }
}


функция find получает список каталогов, ко всем элементам которых будут применена функция, переданная как первый параметр

#человек не написал, ему нужно САМОМУ научиться обходить дерево каталогов, или просто нужно обработать все файлы. Если второе, то не нужно писать так много кода

Автор: Nab 2.8.2006, 11:44
Абсолютно поддерживаю... 
Вообще, наработанную годами базу в виде стандартных модулей и CPAN глупо игнорировать, ее изучать надо и использовать...

Автор: korob2001 2.8.2006, 22:27
Ну не знаю, я лично пытался помочь человеку с этим:
Цитата

а вот как идти дальше во вложенные директории и вернуться обратно - не пойму!

Не думаю, что здесь человек спрашивал о модуле File::Find, насколько я понял она хотела понять принцип того, как предвигаться по каталогам сверху вниз и в обратном направлении.
Да и я считаю, главное понять смысл, потому в первом примере каждая строка прокоментирована. А там глядишь, она напишет свой аналог File::Find, а может ещё чего-нить покруче, независимый от последнего.

ЗЫ: Гораздо надёжнее ездить на автомобиле, зная не то лько ПДД, но ещё и устройство автомобиля. Только не подумайте, что ярый противник CPAN, просто некоторые вещи я делаю вручную, точнее я стараюсь как можно меньше привязываться к какому-нить модулю.

Автор: aksined 3.8.2006, 12:36
Просьба не воспринимать мое сообщение как критику.
Вы готовы помочь - это главное. Причем в ситуациях, когда человек ленится почитать документацию или книгу (ко мне это тоже относится).
Я не сторонник и не протифник cpan.
Просто, мне кажется, что большей части людей, если и будет нужно понять, как произвести обход дерева(с рекурсией или без), потом все равно нужно будет использовать фунцию из модуля (своего или нет). Почему бы не рассказать о стандартных решениях.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)