开发者

How do I read files from an array in perl?

开发者 https://www.devze.com 2023-03-06 11:44 出处:网络
I have read the directory with the files into an array. Now the problem is I would like to open the files and display their contents with a line in between them.

I have read the directory with the files into an array. Now the problem is I would like to open the files and display their contents with a line in between them.

For example, I would like to open file1.txt and file2.txt, and display their contents like this:

Hello nice to meet you -- file 1

How are you? -- file 2

The code is :

sub openFile{
   opendir(fol, "folder/details");
   my @file开发者_开发技巧s= readdir(fol); 
   my @FilesSorted = sort(@files);
   foreach my $EachFile (@FilesSorted) {
      print $EachFile . "\n";
   } 
}


If you just want to display all the lines in the files (as your code seems to be trying to do), without any indication of which line(s) came from which file, there's a trick involving the pre-defined variable @ARGV:

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

If you need to print the file names, you'll have to open each file explicitly:

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;
    }
}


Another example, with some error checking, and skipping sub dirs:

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");


Try

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
   } 
}


Can this be a stand-alone program?

#! /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;
}

Notes

  • The defined check on each value returned from readdir is necessary to handle a file whose name is a false value in Perl, e.g., 0.
  • Your intent is to write the contents of the files in folder/details, so it's also necessary to filter for plain files with the -f test.
  • Perl's built-in processing in while (<>) { ... } shifts arguments off the front of @ARGV. The eofwithout parentheses!—test in the continue clause detects the end of each file and prints newlines as separators between files, not terminators.


You can simplify the directory reading code by using a module like File::Util. It, or some other module like it, will provide several conveniences: error checking; filtering out unwanted directory contents (like the . and .. subdirs); selecting contents by type (for example, just files or dirs); and attaching the root path to the contents.

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";
}

If you prefer to avoid using other modules, you can get the file names like this:

opendir(my $dh, $dir) or die $!;
my @files = grep -f, map("$dir/$_", readdir $dh);


Following up Greg Bacon's answer (re: "Can this be a stand-alone program?"), if you still want this in an openFile subroutine, you could use the same loop there:

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;
  } 
}

Note use of local @ARGV (as in FMc's answer): this preserves any global argument list from outside the subroutine and restores that value on exit.

0

精彩评论

暂无评论...
验证码 换一张
取 消