Как мне прочитать файлы из массива в Perl? - PullRequest
1 голос
/ 18 мая 2011

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

Например, я хотел бы открыть file1.txt и file2.txt и отобразить их содержимое так:

Привет, рад знакомству - файл 1

Как дела? - файл 2

Код:

sub openFile{
   opendir(fol, "folder/details");
   my @files= readdir(fol); 
   my @FilesSorted = sort(@files);
   foreach my $EachFile (@FilesSorted) {
      print $EachFile . "\n";
   } 
}

Ответы [ 6 ]

2 голосов
/ 18 мая 2011

Другой пример, с некоторой проверкой ошибок и пропуском подкаталогов:

sub print_all_files {
  my $dir = shift;
  opendir(my $dh, $dir) || die "Can't read [$dir]: $!";
  while(defined(my $file = readdir $dh)) {
    next unless -f "$dir/$file"; # Ignore subdirs and . and ..
    open(my $fh, "<", "$dir/$file") || die "Can't read [$dir/$file]: $!";
    print while readline($fh);
    print "\n"; # add an extra line
  }
} 

print_all_files("folder/details");
2 голосов
/ 18 мая 2011

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

sub openFile {
    opendir(fol, "folder/details");
    @ARGV = sort(readdir(fol));
    close fol;
    while (<>) {
        print "$_\n";
    }
}

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

sub openFile {
    opendir(fol, "folder/details");
    my @files = sort(readdir(fol));
    close fol;
    while ($file = shift @files) {
        open(FILE, $file);
        while (<FILE>) {
            print "$_\n";
        }
        close FILE;
    }
}
1 голос
/ 18 мая 2011

Может ли это быть автономной программой?

#! /usr/bin/env perl

use strict;
use warnings;

die "$0: no arguments allowed\n" if @ARGV;

my $dir = "folder/details";
opendir my $dh, $dir or die "$0: opendir $dir: $!";

while (defined(my $file = readdir $dh)) {
  my $path = $dir . "/" . $file;
  push @ARGV, $path if -f $path;
}

@ARGV = sort @ARGV;
while (<>) {
  print;
}
continue {
  print "\n" if eof && @ARGV;
}

Примечания

  • Проверка defined для каждого значения, возвращаемого из readdir, необходима для обработки файла, имя которого является ложным значением в Perl, например, , 0.
  • Ваша цель - записать содержимое файлов в folder/details, поэтому также необходимо отфильтровать простые файлы с помощью теста -f.
  • Встроенная обработка Perl в while (<>) { ... } сдвигает аргументы с фронта @ARGV. eof - без круглых скобок! - тест в предложении continue определяет конец каждого файла и печатает переводы строк как разделители между файлами, а не как терминаторы.
1 голос
/ 18 мая 2011

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

use strict;
use warnings;
use File::Util qw();

my $dir = 'folder/details';
my $file_util = File::Util->new;
my @files = $file_util->list_dir($dir, qw(--with-paths --no-fsdots --files-only));

for my $f (@files){
    local @ARGV = ($f);
    print while <>;
    print "\n";
}

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

opendir(my $dh, $dir) or die $!;
my @files = grep -f, map("$dir/$_", readdir $dh);
1 голос
/ 18 мая 2011

Попробуйте

sub openFile{
   opendir(fol, "folder/details");
   my @files= readdir(fol); 
   my @FilesSorted = sort(@files);
   foreach my $EachFile (@FilesSorted) {
      if($EachFile ne "." && $EachFile ne ".." && !(-d $EachFile)) { #important to skip the directories 
        open IT $EachFile || die "unable to read ".$EachFile."\n"; # open file
        while($line = <IT>) {  # print content in file
           print "$line\n";
        }
        close(IT); # close file
        print "-->$EachFile\n";  # print file name
   } 
}
0 голосов
/ 19 мая 2011

После ответа Грега Бэкона (относительно: «Может ли это быть автономная программа?»), Если вы все еще хотите это в подпрограмме openFile, вы можете использовать там тот же цикл:

sub openFile{
  opendir(fol, "folder/details");
  my @files= readdir(fol); 
  my @FilesSorted = sort(@files);
  local @ARGV = @FilesSorted;
  while (<>) {
    print;
  } 
  continue {
    print "\n" if eof && @ARGV;
  } 
}

Обратите внимание на использование local @ARGV (как в ответ FMc ): это сохраняет любой глобальный список аргументов вне подпрограммы и восстанавливает это значение при выходе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...