为什么这个Perl foreach循环只执行一次?

时间:2018-06-15 05:59:26

标签: perl

我正在尝试将三个单独的.vect文件的内容复制到一个文件中。我想对$fromdir目录中的所有5,000个文件执行此操作。

当我运行此程序时,它只在输出目录中生成一个修改过的.vect文件。如果我在close(DATA)循环内的单个while循环后包含foreach调用,我会得到相同的行为:输出目录中的单个输出文件而不是所需的5,000个文件。

我做了一些阅读,起初以为我可能没有打开文件。但如果print($vectfile)循环中的foreach,则打印目录中的每个文件名。

我的第二个想法是我关闭文件的方式,但是 我是否得到了相同的行为 我关闭foreach循环内部或外部的文件句柄。

我最后的想法可能是我没有对文件或目录的书面许可,但我不知道如何更改它。

如何让这个循环运行5000次而不只是一次?

use strict;
use warnings;
use feature qw(say);

my $dir = "D:\\Downloads";

# And M3.1 and P3.1
my $subfolder = "A0.1";

my $fromdir = $dir . "\\" . $subfolder;

my @files = <$fromdir/*vect>;

# Top of file
my $readfiletop = "C:\\Users\\Owner\\Documents\\MoreKnotVis\\ScriptsForAdditionalDataSets\\VectFileHeader.vect";

# Bottom of file
my $readfilebottom = "C:\\Users\\Owner\\Documents\\MoreKnotVis\\ScriptsForAdditionalDataSets\\VectFileCloser.vect";


foreach my $vectfile ( @files ) {

    say("$vectfile");

    my $count        = 0;
    my $readfilebody = $vectfile;
    my $out_file     = "D:\\Downloads\\ColorsA0.1\\" . "$count" . ".vect";

    $count++;

    # open top part of each file
    open(DATA1, "<", $readfiletop) or die "Can't open '$readfiletop': $!";

    # open bottom part of each file
    open(DATA3, "<",  $readfilebottom) or die "Can't open '$readfilebottom': $!";

    # open a file to read
    open(DATA2, "<", $vectfile) or die "Can't open '$vectfile': $!";

    # open a file to write to
    open(DATA4, ">" ,$out_file) or die "Can't open '$out_file': $!";

    # Copy data from VectFileTop file to another.
    while ( <DATA1> ) {
        print DATA4 $_; 
    }

    # Copy the data from VectFileBody to another.
    while ( <DATA2> ) {
        print DATA4 $_, $_ if 8..12;
    }


    # Copy the data from VectFileBottom to another.
    while ( <DATA3> ) {
        print DATA4 $_;
    }    
}

close( DATA1 );
close( DATA2 );
close( DATA3 );
close( DATA4 );

print("quit\n");

2 个答案:

答案 0 :(得分:3)

您可以在其中构建包含$count的输出文件名。

但请注意您对此变量的处理方式:

  • 最初,但在循环内,您将其设置为0,
  • 输出文件名由0构成,
  • 然后你增加它,但这没有效果,因为这个变量 在下一次执行循环时再次设置为0 ..

效果是:

  • 循环执行所需的数字,
  • 但输出文件名每次包含0作为&#34;数字&#34;, 所以你不断用新内容覆盖同一个文件

在循环之前移动my $count = 0;指令以及所有内容 应该没问题。

答案 1 :(得分:3)

如果改变一件事,你似乎依赖于某种特定形式的代码,因为害怕一切都崩溃了。我建议您敢于从公式中稍微偏离一点,以便代码更简洁和可读

问题是在处理每个输入文件之前将$count重置为零,因此所有输出文件都具有相同的名称并相互覆盖。剩余的输出文件仅包含 last 输入文件

中的数据

这是您的代码的重构。我不能保证它会正确运行但它看起来正确并且编译

  • 我已添加use autodie以避免检查每个IO操作的状态

  • 我为所有输入文件使用了相同的词法文件句柄$fh。在已经打开的文件句柄上打开另一个文件将首先关闭它,当它在块结束时超出范围时,将由perl关闭词法文件句柄

  • 我使用while循环迭代输入文件名而不是将整个列表读入一个不必要地使用额外变量@files的数组并浪费空间< / p>

  • 我在所有文件路径中都使用了正斜杠而不是反斜杠。这在Windows上的库调用中很好:如果它们出现在命令行输入中,它只是一个问题

我希望您同意此表单更具可读性。如果您的代码采用这种形式,我认为如果找到问题,你会有更好的机会

use strict;
use warnings;
use autodie;
use feature qw/ say /;

my $indir     = 'D:/Downloads';
my $subdir    = 'A0.1';                    # And M3.1 and P3.1
my $extrasdir = 'C:/Users/Owner/Documents/MoreKnotVis/ScriptsForAdditionalDataSets';

my $outdir     = "$indir/Colors$subdir";
my $topfile    = "$extrasdir/VectFileHeader.vect";
my $bottomfile = "$extrasdir/VectFileCloser.vect";

my $filenum;

while ( my $vectfile = glob "$indir/$subdir/*.vect" ) {

    say qq/Processing "$vectfile"/;

    $filenum++;

    open my $outfh, '>', "$outdir/$filenum.vect";

    my $fh;

    open $fh, '<', $topfile;
    print { $outfh } $_ while <$fh>;

    open $fh, '<', $vectfile;
    while ( <$fh> ) {
        print { $outfh } $_, $_ if 8..12;
    }

    open $fh, '<', $bottomfile;
    print { $outfh } $_ while <$fh>;
}

say 'DONE';