我尝试打开文件夹中的文件列表。最后我想在其中插入一个HTML-Snippet。到目前为止,我可以打开文件夹并读取数组中的列表。没关系。但是当我尝试使用变量作为文件名打开文件时,我每次都会收到一条错误消息(“权限被拒绝”)。无论我使用$ _还是将列表项的值放在变量中的其他变体。我在这里找到了类似的问题,但到目前为止还没有找到解决方案。这是我的代码:
use strict;
use warnings;
my ($line);
opendir (FOLDER,"path/to/folder/./") or die "$!";
my @folderlist = readdir(FOLDER);
my @sorted_folderlist = sort @folderlist;
close(FOLDER);
foreach (@sorted_folderlist) {
my $filename = $_;
open (READ, ">", "path/to/folder/$filename") or die "$!";
# do something
close (READ);
}
这里的错误是什么?我如何使用变量作为文件名打开文件?
Pjoern
这是我更改的代码,以便回答1:
my $dh;
opendir $dh, "dir/./" or die ...
my @folderlist = grep { -f "dir/$_" } readdir $dh;
close $dh;
my @sorted_folderlist = sort @folderlist;
foreach my $filename (@sorted_folderlist) {
open my $fh, "<", "dir/$filename" or die ...
open my $writeto, ">", "new/$filename" or die ...
print $writeto "$fh";
close $fh;
close $writeto;
}
答案 0 :(得分:8)
您的代码中存在多个问题。
第一个导致错误的可能是,readdir()
也将返回.
和..
,但这些是目录。所以你试着写信给directory/.
。
其次,您的错误消息包含$!
,这很好,但您不输出文件名。然后你会看到你的错误。
第三,你打电话给你打开的文件句柄READ
。
此外,您现在应该使用词法文件句柄。
use strict;
use warnings;
opendir my $dh, "dir" or die $!;
# read all files, not directories
my @folderlist = grep { -f "dir/$_" } readdir $dh;
close $dh;
my @sorted_folderlist = sort @folderlist;
foreach my $filename (@sorted_folderlist) {
open my $fh, ">", "dir/$filename" or die "Could not write to dir/$filename: $!";
print $fh "foo...\n";
close $fh;
}
答案 1 :(得分:7)
您已在tinita's answer中清除错误和良好做法。
我想评论一下可能的改进,即建立一个完整路径的文件列表。
在readdir
的输出上使用map将目录添加到每个文件,然后过滤
my @files = grep { -f } map { "$dir/$_" } readdir $dh;
或在map
块
my @files = map { my $fp = "$dir/$_"; -f $fp ? $fp : () } readdir $dh;
如果$fp
不是-f
,我们会返回一个空列表,该列表会在输出中变平,从而消失。
使用glob,它直接为您提供完整路径†
use File::Glob ':bsd_glob';
my @files = grep { -f } glob "$dir/*";
其中File::Glob的bsd_glob()
会覆盖glob
并很好地处理名称中的空格。
注意区别:*
中的glob
不会选择以点(.
)开头的条目。如果您也想要这些,请将其更改为glob "$dir/{*,.*}"
。请参阅关联的File::Glob
文档。
更新以更正问题的编辑(添加),也在评论中讨论
将完整路径文件名读入@files
foreach my $file (@files) {
my $out_file = 'new_' . $file;
open my $writeto '>', $outfile or die "Can't open $outfile: $!";
open my $fh, '<', $file or die "Can't open $file: $!";
while (my $line = <$fn>) {
# process $line and build what need be written to the new file
my $new_line = ...
print $writeto $new_line;
}
close $writeto;
close $fh;
}
(或者,如果文件名不是完整路径,则在open
调用中构建完整路径。)
再次打开时,文件句柄会关闭,因此您只需要为最后一个文件显式close
。然后,您可以在循环之前声明my ($fh, $writeto);
变量,使用open $fh ...
(无my
),然后关闭文件句柄。但是那时你有foreach
范围之外的那些变量。
文档:
†对于非常特殊的目录名,glob "$dir/*"
可能存在注入错误。
虽然这只会产生相当不寻常的名称,但使用escape sequence
my @files = grep { -f } glob "\Q$dir\E/*"
由于这会占用空格,因此不需要File::Glob
及其bsd_glob()
。