我在主文件夹中有几个子文件夹。每个子文件夹中都有一个.txt文件。首先,代码将创建"结果"主文件夹中的文件夹。它会搜索" atom" .txt中的单词并打印到输出文件(在结果文件夹中)作为列包括" Frequencies - "字。它将为子文件夹中的每个.txt文件执行此过程。输出文件名可以与子文件夹相同。代码创建"结果"文件夹,但它给出以下错误。我该如何解决?
Error:Failed to open "./freq.txt" for writing: No such file or directory at ./analysis.pl line 27
#!/usr/bin/env perl
use strict;
use warnings;
use File::Path qw/make_path/;
use Cwd;
my $dir = cwd();
opendir (my $dh, $dir) or die "Unable to open current directory! $!\n";
my @subdirs = grep { /^\.\.?\z/ } readdir($dh) or die "Unable to read directory! $!\n";
closedir $dh;
my $result_path = "$dir/results";
make_path("$result_path");
for my $subdir ( sort @subdirs ) {
chdir($dir);
next unless -d $subdir;
make_path("$result_path/$subdir");
my $search_text1 = qr/Frequencies --/;
my $infile1="$subdir/freq.txt";
my $outfile1="$result_path/output.txt";
# Line 27 below
open my $in_fh1, '<', $infile1 or die qq{Failed to open "$infile1" for writing: $!};
open my $out_fh1,'>', $outfile1 or die qq{Failed to open "$outfile1" for writing: $!};
while (<$in_fh1>) {
next unless /$search_text1/;
my @fields1 = split;
print $out_fh1 join("\t", $fields1[1,2,3]), "\n";
}
close($in_fh1);
close($out_fh1);
chdir("..");
}
输入文件:
Frequencies -- 23.5214 40.9023 56.7856
Red. masses -- 6.7793 1.0546 5.5674
Frc consts -- 0.0022 0.0010 0.0106
IR Inten -- 2.4504 0.2236 0.6152
Atom AN X Y Z X Y Z X Y Z
1 6 0.00 0.01 0.06 0.00 0.00 0.01 0.00 -0.01 0.11
2 6 0.00 0.00 0.09 0.00 0.00 0.01 0.00 0.00 0.10
3 7 0.00 0.01 0.19 0.00 0.00 0.03 0.00 0.00 0.02
Frequencies -- 91.1714 97.2522 123.2844
Red. masses -- 7.3071 9.6551 6.3036
Frc consts -- 0.0358 0.0538 0.0564
IR Inten -- 0.5639 11.9103 2.8105
Atom AN X Y Z X Y Z X Y Z
1 6 0.01 -0.14 -0.01 -0.01 0.04 0.04 0.00 0.00 -0.23
2 6 0.00 -0.12 0.02 0.00 0.04 0.02 0.01 0.01 0.17
3 7 0.00 -0.14 -0.05 0.00 0.04 -0.22 0.01 0.00 -0.15
答案 0 :(得分:3)
您的代码存在许多问题。
您的错误消息不正确。您正在报告您尝试打开文件以便在打开文件时进行阅读。重新格式化,它更容易阅读。
# This says it's open for writing, but its for reading.
open my $in_fh1, '<', $infile1
or die qq{Failed to open "$infile1" for writing: $!};
open my $out_fh1, '>', $outfile1
or die qq{Failed to open "$outfile1" for writing: $!};
您的问题是freq.txt
不存在。
autodie将使您的所有IO函数抛出良好的错误消息。它已经与Perl一起发售了一段时间了。只需将use autodie
放在您的脚本中,通常靠近use strict
等等,您就不必再在整个地方写or die ...
。
use strict;
use warnings;
use autodie;
...later on...
open my $in_fh1, '<', $infile1;
open my $out_fh1, '>', $outfile1;
这一行也是一个问题。
my @subdirs = grep { /^\.\.?\z/ } readdir($dh) or die "Unable to read directory! $!\n";
如果opendir成功,则不需要检查readdir(现在将使用autodie完成)。更大的问题是@subdirs
只包含.
和..
我怀疑你想要的。你需要否定那场比赛。使用m{}
来避免leaning toothpick syndrome也很有帮助。
opendir(my $dh, $dir);
my @subdirs = grep { !m{^\.\.?\z} } readdir($dh);
closedir $dh;
Path::Tiny将为您处理这项工作。它没有Perl,但它非常容易安装并且非常有用。它可以将代码简化为......
my @subdirs = path(".")->children;
Path :: Tiny非常有用,它将消除大量代码。你不再需要加载一个模块来创建一个目录而另一个模块需要找到你所在的目录,而另一个模块需要操作路径而另一个模块需要...你得到了这个想法。它还会在失败时抛出错误,因此您无需在所有内容上编写or die
。
下一个问题是你有一行chdir($dir)
,但$dir
是当前的工作目录,所以什么都不做。稍后在循环中你chdir("..")
所以你将慢慢爬上目录树。我不知道你的意图是什么。对于特定的绝对目录,chdir
通常比相对的目录更强大。如果你的代码失去了对它的位置的跟踪,它就会自行解决。
我认为你不需要更改目录,所以我只是消除它。
将所有内容放在一起,并在适用的情况下使用Path :: Tiny ......
#!/usr/bin/env perl
use strict;
use warnings;
use autodie;
use Path::Tiny;
# Get the current directory. We could just use "." but this
# has the nice effect of giving us an absolute directory in case
# we chdir.
my $dir = Path::Tiny->cwd();
# Create a directory to hold the results.
my $result_path = $dir->child("results");
$result_path->mkpath;
# Loop through the sub directories.
for my $subdir ( sort $dir->children ) {
next unless -d $subdir;
# Make a matching sub-directory in the results directory
# I believe there is a mistake, this directory is never
# used. I suspect output.txt needs to go in here.
$result_path->child($subdir)->mkpath;
# Open the frequency file and an output file for it.
# I believe there is a mistake here, each iteration of the
# loop will overwrite output.txt. I believe it was
# supposed to use the directory created above.
my $infile1 = $subdir->child("freq.txt");
my $outfile1 = $result_path->child("output.txt");
# Open them for reading and writing.
my $in_fh1 = $infile1->openr;
my $out_fh1 = $outfile1->openw;
# Process just the Frequencies line.
while (<$in_fh1>) {
next unless /Frequencies --/;
# There is a mistake here, this will split "Frequencies --"
# into two parts. You want @fields1[2,3,4] or better yet
# strip the header with "next unless s/^Frequencies --//;"
my @fields1 = split;
# An array slice uses @. It should be @fields1[...]
print $out_fh1 join("\t", $fields1[1,2,3]), "\n";
}
}
处理中仍有许多错误。我在评论中注意到了这些,但这个答案已经太久了。