我尝试打开文件夹中的文件列表.最后我想在其中插入一个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);
}
Run Code Online (Sandbox Code Playgroud)
这里有什么错误?我如何使用变量作为文件名打开文件?
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;
}
Run Code Online (Sandbox Code Playgroud)
您的代码中有几个问题.
第一,导致了错误,很可能是,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;
}
Run Code Online (Sandbox Code Playgroud)
你在锡蒂塔的回答中找到了错误和良好做法.
我想评论一下可能的改进,即构建具有完整路径的文件列表.
在输出上使用mapreaddir将目录添加到每个文件,然后对其进行过滤
my @files = grep { -f } map { "$dir/$_" } readdir $dh;
Run Code Online (Sandbox Code Playgroud)
或者,在块中实现grep(过滤)功能 map
my @files = map { my $fp = "$dir/$_"; -f $fp ? $fp : () } readdir $dh;
Run Code Online (Sandbox Code Playgroud)
在这里,如果$fp不是,-f我们返回一个空列表,在输出中变平,从而消失.
使用glob,它直接为你提供完整的路径†
use File::Glob ':bsd_glob';
my @files = grep { -f } glob "$dir/*";
Run Code Online (Sandbox Code Playgroud)
其中,文件::水珠的bsd_glob()覆盖glob和处理空间的名字好听.
注意区别:*in glob不会选择以dot(.)开头的条目.如果您也想要这些,请将其更改为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;
}
Run Code Online (Sandbox Code Playgroud)
(或者,如果文件名不是完整路径,则构建open调用中的完整路径.)
再次打开时,close文件句柄会关闭,因此您只需要显示最后一个文件.然后你可以my ($fh, $writeto);在循环之前声明变量,使用open $fh ...(no my),然后关闭文件句柄.但是你有那些变量超出foreach范围.
文档:
†glob "$dir/*"对于非常特殊的目录名称, 它具有注入错误的可能性.虽然这只能产生相当不寻常的名称,但使用转义序列会更安全
my @files = grep { -f } glob "\Q$dir\E/*"
Run Code Online (Sandbox Code Playgroud)
由于该逃逸空间以及在File::Glob与它bsd_glob()是没有必要的.