【问题标题】:Perl Error: No such file or directoryPerl 错误:没有这样的文件或目录
【发布时间】:2015-03-10 00:40:23
【问题描述】:

我在主文件夹中有几个子文件夹。每个子文件夹中都有一个 .txt 文件。首先,代码将在主文件夹中创建“结果”文件夹。它将在 .txt 中搜索“atom”字,并将包含“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

【问题讨论】:

  • 您正试图打开伪目录... 中的文件,而不是真正的子目录。你似乎在反复问非常相似的问题,然后忽略了你得到的答案。您为什么不使用您对上一个问题接受的解决方案?
  • 当您发布脚本时,请至少正确缩进,以便其他人阅读。

标签: perl


【解决方案1】:

你的代码有很多问题。

您的错误信息不正确。您报告您在打开文件进行读取时尝试打开文件进行写入。重新格式化,阅读起来更容易一些。

# 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";
    }
}

处理过程中还有很多错误。我已经在 cmets 中注意到了它们,但是这个答案已经太长了。

【讨论】:

  • 谢谢@Schwern。你的代码很棒。我想知道如何在my $search_text1 = qr/Frequencies/; 部分中将“频率”单词的第一个字母大写?
  • @perlselami 这最好作为另一个问题来完成。
猜你喜欢
  • 2021-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 2013-11-04
  • 2012-02-18
  • 2012-10-21
  • 2011-03-22
相关资源
最近更新 更多