简体   繁体   English

Perl - 无法打开和读取文件

[英]Perl - Could not open and read files

I've created a script for validating xml files after given input folder.我创建了一个脚本,用于在给定的输入文件夹后验证 xml 文件。 It should grep xml files from the input directory then sort out the xml files and check the condition.它应该从输入目录中 grep xml 文件,然后整理 xml 文件并检查条件。 But it throws a command that not Open at line , <STDIN> line 1 .但它抛出的命令not Open at line , <STDIN> line 1

But it creates an empty log file.但它会创建一个空的日志文件。

Since i faced numeric error while sorting, comment that.由于我在排序时遇到numeric错误,请对此发表评论。

so i need to be given input location, the script should check the xml files and throw errors in a mentioned log file.所以我需要得到输入位置,脚本应该检查 xml 文件并在提到的日志文件中抛出错误。

Anyone can help this?任何人都可以帮助这个?

Script脚本

#!/usr/bin/perl
# use strict;
use warnings;
use Cwd;
use File::Basename;
use File::Path;
use File::Copy;
use File::Find;

print "Enter the path: ";
my $filepath = <STDIN>;
chomp $filepath;

die "\n\tpleas give input folder \n" if(!defined $filepath or !-d $filepath);

my $Toolpath = dirname($0);
my $base = basename($filepath);
my $base_path = dirname($filepath);

my ($xmlF, @xmlF);

my @errors=();
my @warnings=();
my @checkings=();
my $ecount=0;
my $wcount=0;
my $ccount=0;
my ($x, $y);
my $z="0";

opendir(DIR,"$filepath");
my @xmlFiles = grep{/\.xml$/} readdir(DIR);
closedir(DIR);

my $logfile = "$base_path\\$base"."_Err.log";

# @xmlF=sort{$a <=> $b}@xmlFiles;
@xmlF=sort{$a cmp $b}@xmlFiles;

open(OUT, ">$logfile") || die ("\nLog file couldnt write $logfile :$!");


my $line;

my $flcnt = scalar (@xmlF);

for ($x=0; $x < $flcnt; $x++)
{
open IN, "$xmlF[$x]" or die "not Open";
print OUT "\n".$xmlF[$x]."\n==================\n";
print "\nProcessing File $xmlF[$x] .....\n";
local $/;

while ($line=<IN>)
{
while ($line=~m#(<res(?: [^>]+)? type="weblink"[^>]*>)((?:(?!</res>).)*)</res>#igs)
{
    my $tmp1 = $1; my $tmp2 = $&; my $pre1 = $`;
    if($tmp1 =~ m{ subgroup="Weblink"}i){
        my $pre = $pre1.$`;
        if($tmp2 !~ m{<tooltip><\!\[CDATA\[Weblink\]\]><\/tooltip>}ms){
            my $pre = $pre1.$`;
            push(@errors,lineno($pre),"\t<tooltip><\!\[CDATA\[Weblink\]\]></tooltip> is missing\n");
        }
    }
}
foreach my $warnings(@warnings)
{
$wcount = $wcount+1;
}
foreach my $checkings(@checkings)
{
$ccount = $ccount+1;
}
foreach my $errors(@errors)
{
$ecount = $ecount+1;
}

my $count_err = $ecount/2;
print OUT "".$count_err." Error(s) Found:-\n------------------------\n ";
print OUT "@errors\n";
$ecount = 0;

my $count_war = $wcount/2;
print OUT "$count_war Warning(s) Found:-\n-------------------------\n ";
print OUT "@warnings\n";
$wcount = 0;

my $count_check = $ccount/2;
print OUT "$count_check Checking(s) Found:-\n-------------------------\n ";
print OUT "@checkings\n";
$wcount = 0;

undef @errors;
undef @warnings;
undef @checkings;

close IN;
}
}

The readdir returns bare file names, without the path. readdir返回裸文件名,没有路径。

So when you go ahead to open those files you need to prepend the names returned by readdir with the name of the directory the readdir read them from, here $filepath .因此,当您继续打开这些文件时,您需要在readdir返回的名称前面加上readdir从中读取它们的目录的名称,这里是$filepath Or build the full path names right away或者立即构建完整的路径名

use warnings;
use strict;
use feature 'say';
use File::Spec;

print "Enter the path: ";
my $filepath = <STDIN>;
chomp $filepath;

die "\nPlease give input folder\n" if !defined $filepath or !-d $filepath;

opendir(my $fh_dir, $filepath) or die "Can't opendir $filepath: $!";

my @xml_files = 
    map { File::Spec->catfile($filepath, $_) } 
    grep { /\.xml$/ } 
    readdir $fh_dir;

closedir $fh_dir;

say for @xml_files;

where I used File::Spec to portably piece together the file name.我使用File::Spec将文件名可移植地拼凑在一起。

The map can be made to also do grep 's job so to make only one pass over the file list map也可以做grep的工作,以便只对文件列表进行一次传递

my @xml_files = 
    map { /\.xml$/ ? File::Spec->catfile($filepath, $_) : () } 
    readdir $fh_dir;

The empty list () gets flattened in the returned list, effectively disappearing altogether.空列表()在返回的列表中变平,实际上完全消失了。


Here are some comments on the code.下面是对代码的一些注释。 Note that this is normally done at Code Review but I feel that it is needed here.请注意,这通常在Code Review 中完成,但我觉得这里需要它。

First: a long list of variables is declared upfront.首先:预先声明一长串变量。 It is in fact important to declare in as small a scope as possible.事实上,在尽可能小的范围内声明很重要。 It turns out that most of those variables can indeed be declared where they are used, as seen in comments below.事实证明,这些变量中的大多数确实可以在使用它们的地方声明,如下面的评论所示。

  • The location of the executable is best found using最好使用以下命令找到可执行文件的位置

    use FindBin qw($RealBin);

    where $RealBin also resolves links (as opposed to $Bin , also available)其中$RealBin也解析链接(与$Bin相反,也可用)

  • Assigning () to an array at declaration doesn't do anything;在声明时将()赋值给数组不会做任何事情; it is exactly the same as normal my @errors;它和正常的my @errors;完全一样my @errors; . . They can also go together, my (@errors, @warnings, @checks);他们也可以一起去, my (@errors, @warnings, @checks); . . If the array has something then = () clears it, what is a good way to empty an array如果数组有东西然后= ()清除它,什么是清空数组的好方法

  • Assigning a "0" makes the variable a string.分配"0"使变量成为字符串。 While Perl normally converts between strings and numbers as needed, if a number is needed then use a number, my $z = 0;虽然 Perl 通常会根据需要在字符串和数字之间进行转换,但如果需要数字,则使用数字, my $z = 0;

  • Lexical filehandles ( open my $fh, ... ) are better than globs ( open FH, ... )词法文件句柄( open my $fh, ... )比 globs ( open FH, ... )更好

  • I don't understand the comment about " numeric error " in sorting.我不明白排序中关于“数字错误”的评论。 The cmp operator sorts lexicographically, for numeric sort use <=> cmp运算符按字典顺序排序,对于数字排序使用<=>

  • When array is used in scalar context – when assigned to a scalar for example – the number of elements is returned.当数组在标量上下文中使用时——例如分配给标量时——返回元素的数量。 So no need for scalar but do my flcnt = @xmlF;所以不需要scalar而是做my flcnt = @xmlF;

  • For iteration over array indices use $#ary , the index of the last element of @ary , for对于数组索引的迭代,使用$#ary ,@ $#ary最后一个元素的@ary ,对于

    foreach my $i (0..$#xmlF) { ... }

    But if there aren't any uses of the index (I don't see any) then loop over elements但是如果索引没有任何用途(我看不到任何用途),则循环遍历元素

    foreach my $file (@xmlF) { ... }
  • When you check the file open print the error $!当您检查文件open打印错误$! , open ... or die "... : $!"; , open ... or die "... : $!"; . . This is done elsewhere in the code, and it should be done always.这是在代码的其他地方完成的,并且应该始终完成。

  • The local $/; local $/; unsets the input record separator , what makes the following read take the whole file.取消设置输入记录分隔符,是什么使以下读取占用整个文件。 If that is intended then $line is not a good name.如果这是故意的,那么$line不是一个好名字。 Also note that a variable can be declared inside the condition, while (my $line = <$fh>) { }另请注意,可以在条件内部声明变量, while (my $line = <$fh>) { }

  • I can't comment on the regex as I don't know what it's supposed to accomplish, but it is complex;我无法评论正则表达式,因为我不知道它应该完成什么,但它很复杂; any chance to simplify all that?有机会简化这一切吗?

  • The series of foreach loops only works out the number of elements of those arrays;一系列foreach循环只计算这些数组的元素数; there is no need for loops then, just my $ecount = @errors;那么就不需要循环了,只需要my $ecount = @errors; (etc). (等等)。 This also allows you to keep the declaration of those counter variables in minimal scope.这也允许您将这些计数器变量的声明保持在最小范围内。

  • The undef @errors; undef @errors; (etc) aren't needed since those arrays count for each file and so you can declare them inside the loops, anew at each iteration (and at smallest scope). (etc) 不是必需的,因为这些数组对每个文件都有计数,因此您可以在循环内声明它们,在每次迭代时(以及最小范围内)重新声明。 When you wish to empty an array it is better to do @ary = ();当您希望清空数组时,最好执行@ary = (); than to undef it;而不是undef它; that way it's not allocated all over again on the next use这样它就不会在下次使用时重新分配

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM