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



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

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

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

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

我最后的想法是,也许我没有对文件或目录的写入权限,但我不知道如何更改它。

如何让此循环运行全部 5,000 次,而不仅仅是一次?

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("quitn");

构造输出文件名(包括其中的$count(。

但请注意您对此变量执行的操作:

  • 最初,但在循环中将其设置为 0,
  • 输出文件名是用0构造的,
  • 然后你递增它,但这没有效果,因为这个变量 在循环的下一次执行中再次设置为 0。

其效果是:

  • 循环执行所需的次数,
  • 但是每次输出文件名包含0作为"数字", 因此,您不断用新内容覆盖同一文件

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

你似乎坚持一种特定形式的代码,害怕如果你改变一件事,一切都会分崩离析。我建议你敢于从公式中多偏离一点,这样代码就更简洁易读了

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

下面是代码的重构。我不能保证它会正确运行,但它看起来正确并且可以编译

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

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

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

  • 我在所有文件路径中使用了正斜杠而不是反斜杠。这在 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';

最新更新