Как открыть файл, который присутствует в другом файле рекурсивно в Perl - PullRequest
0 голосов
/ 07 октября 2018

Рекурсивные открытия файлов без уничтожения файловых дескрипторов в perl

#!usr/bin/perl
   $set=1; 
   open (MYFILE, 'file1.txt'); 
   $array[$set]=\*MYFILE; 
   printit ($array[$set]); 

   sub printit {    
     ($array[$set])=shift;    
     $fh=<$array[$set]>;
     while (<$fh>) {
       chomp($fh); 
       #print data in the file
       if($fh=~/\.txt/){
           #print $fh;
           open (files,"$fh");
           $set=$set+1;
           printit(*files);
           $set=$set-1;
          }
    } 
}   
file1.txt -file2.txt,file3.txt #assume file2.txt comes before file3.txt 
file2.txt-file4.txt file3.txt 

Я хочу открыть file1.txt и распечатать данные в file1, и если я найду file2.txt в файле, откройте файлпечатать данные и идти рекурсивно, пока файл не содержит и файлы .txt присутствуют в нем и возвращается (поперек тресса) в нашем случае file1-> file2-> file4-> file3-> file1 end program.Я не знаю, почему моя программа не работает.Заранее спасибо *

1 Ответ

0 голосов
/ 07 октября 2018

Мой взгляд на проблему: прочитайте файл и, если найдены имена файлов (судя по .txt), откройте и прочитайте их, и продолжайте рекурсивно.В опубликованном коде есть несколько основных ошибок, которые обсуждаются ниже.

Я предполагаю, что сначала должны быть напечатаны все строки файла, а затем мы переходим к следующему файлу (файлам) (если он найден).Код ниже позволяет закрывать файловые дескрипторы;за ним следует небольшое изменение, которое хранит их в массиве и открывает их.

use warnings;
use strict;
use feature 'say';

my $file = shift @ARGV || 'file.txt';

open my $fh, '<', $file or die "Can't open $file: $!";

recurse_open($fh);

sub recurse_open {
    my ($fh) = shift;
    my @files;
    while (<$fh>) {
        print;
        if (/\b(.+?\.txt)\b/) {
            push @files, $1; 
        }   
    }   
    say '---';
    foreach my $file (@files) {
        open my $fh_next, '<', $file  or do {
            warn "Can't open $file: $!";
            next;
        };
        recurse_open($fh_next);
    }   
}

Это печатает

main file
file1.txt is in it
end of main file
---
file one, with
a line with file2.txt
end of one
---
file two, which has
a line with file3.txt
end of two
---
Just the file3,
no more filenames.
---

, где содержимое file.txt и файлы 1..3понятно, надеюсь (отделено ---).Это следует за всеми именами файлов, присутствующими в файле, если случается, что их больше одного.

Если фраза " без уничтожения файловых дескрипторов " в заголовке означает, что файловые дескрипторы должныбыть открытым (и собранным), а затем просто добавлять их в массив по мере их открытия

open my $fh, '<', $file or die "Can't open $file: $!";
my @filehandles = ($fh);

recurse_open($fh, \@filehandles);

sub recurse_open {
    my ($fh, $handles) = @_;
    ...
    foreach my $file (@files) {
        open my $fh_next, '<', $file  or do {
            warn "Can't open $file: $!";
            next;
        };    
        push @$handles, $fh_next;
        recurse_open($fh_next, $handles);
    }
}

Обычно (лексический) дескриптор файла закрывается, когда он выходит из области видимости.Однако, поскольку каждый из них теперь копируется в массив, определенный в большей области, они сохраняются, поскольку для каждого есть ссылка.


Комментарии к коду в вопросе.

Самая серьезная ошибка - это очевидное неправильное понимание того, что такое файловый дескриптор и что делает.Выражение <$fh> считывает из файла, который был связан с дескриптором файла $fh, когда он был открыт, где <> - версия оператора readline .См. Операторы ввода / вывода в perlop .

Возвращает строку в файле, и , что - это то, над чем вы должны работать, с chomp, m//и т. д., а не на самом $fh.При while (<$fh>) (в условии ничего больше) строка присваивается специальной переменной $_, которая по умолчанию для многих вещей в Perl.Приведенный выше код использует это.

Далее, вы фактически не сопоставляете и не фиксируете имя файла, а только сопоставляете только .txt.(Это совпадение использует файловый дескриптор вместо переменной, содержащей строку, а open использует этот файловый дескриптор вместо имени файла, что является путаницей файлового дескриптора, упомянутой выше.)

Тогда я не вижунужно для этого танцевать около $set, увеличивая и уменьшая его.Поскольку вы прекрасно перенесли все это в подпрограмму, просто используйте дескриптор файла в переменной.Так что я покончил с массивом.Пожалуйста, восстановите его, если это необходимо по каким-то другим причинам.

Наконец:

  • Всегда Запустите программу с use warnings; и use strict;,Это не какая-то педантичность, но напрямую помогает отлавливать ошибки и применяет некоторые очень хорошие практики.

  • Всегда проверяйте openзвоните (open ... or ...)

  • Используйте лексические дескрипторы файлов (my $fh) вместо globs (FH), они намного лучше.Используйте версию с тремя аргументами open

Если это целая цель, вы можете также передать имя файла рекурсивной подпрограмме и открыть его и прочитать файл.

...