簡體   English   中英

Perl - 無法打開和讀取文件

[英]Perl - Could not open and read files

我創建了一個腳本,用於在給定的輸入文件夾后驗證 xml 文件。 它應該從輸入目錄中 grep xml 文件,然后整理 xml 文件並檢查條件。 但它拋出的命令not Open at line , <STDIN> line 1

但它會創建一個空的日志文件。

由於我在排序時遇到numeric錯誤,請對此發表評論。

所以我需要得到輸入位置,腳本應該檢查 xml 文件並在提到的日志文件中拋出錯誤。

任何人都可以幫助這個?

腳本

#!/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;
}
}

readdir返回裸文件名,沒有路徑。

因此,當您繼續打開這些文件時,您需要在readdir返回的名稱前面加上readdir從中讀取它們的目錄的名稱,這里是$filepath 或者立即構建完整的路徑名

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;

我使用File::Spec將文件名可移植地拼湊在一起。

map也可以做grep的工作,以便只對文件列表進行一次傳遞

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

空列表()在返回的列表中變平,實際上完全消失了。


下面是對代碼的一些注釋。 請注意,這通常在Code Review 中完成,但我覺得這里需要它。

首先:預先聲明一長串變量。 事實上,在盡可能小的范圍內聲明很重要。 事實證明,這些變量中的大多數確實可以在使用它們的地方聲明,如下面的評論所示。

  • 最好使用以下命令找到可執行文件的位置

    use FindBin qw($RealBin);

    其中$RealBin也解析鏈接(與$Bin相反,也可用)

  • 在聲明時將()賦值給數組不會做任何事情; 它和正常的my @errors;完全一樣my @errors; . 他們也可以一起去, my (@errors, @warnings, @checks); . 如果數組有東西然后= ()清除它,什么是清空數組的好方法

  • 分配"0"使變量成為字符串。 雖然 Perl 通常會根據需要在字符串和數字之間進行轉換,但如果需要數字,則使用數字, my $z = 0;

  • 詞法文件句柄( open my $fh, ... )比 globs ( open FH, ... )更好

  • 我不明白排序中關於“數字錯誤”的評論。 cmp運算符按字典順序排序,對於數字排序使用<=>

  • 當數組在標量上下文中使用時——例如分配給標量時——返回元素的數量。 所以不需要scalar而是做my flcnt = @xmlF;

  • 對於數組索引的迭代,使用$#ary ,@ $#ary最后一個元素的@ary ,對於

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

    但是如果索引沒有任何用途(我看不到任何用途),則循環遍歷元素

    foreach my $file (@xmlF) { ... }
  • 當您檢查文件open打印錯誤$! , open ... or die "... : $!"; . 這是在代碼的其他地方完成的,並且應該始終完成。

  • local $/; 取消設置輸入記錄分隔符,是什么使以下讀取占用整個文件。 如果這是故意的,那么$line不是一個好名字。 另請注意,可以在條件內部聲明變量, while (my $line = <$fh>) { }

  • 我無法評論正則表達式,因為我不知道它應該完成什么,但它很復雜; 有機會簡化這一切嗎?

  • 一系列foreach循環只計算這些數組的元素數; 那么就不需要循環了,只需要my $ecount = @errors; (等等)。 這也允許您將這些計數器變量的聲明保持在最小范圍內。

  • undef @errors; (etc) 不是必需的,因為這些數組對每個文件都有計數,因此您可以在循環內聲明它們,在每次迭代時(以及最小范圍內)重新聲明。 當您希望清空數組時,最好執行@ary = (); 而不是undef它; 這樣它就不會在下次使用時重新分配

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM