我正在尝试将三个单独的.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';