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 fromreaddir
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
. Theeof
—without parentheses!—test in thecontinue
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.
精彩评论