perl打开文件名中包含变量的文件

时间:2017-12-15 21:49:45

标签: arrays perl file

我尝试打开文件夹中的文件列表。最后我想在其中插入一个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; 
}

2 个答案:

答案 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

    中实现grep的(过滤)功能
    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::Globbsd_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()