Perl,在主程序和子程序中移动文件句柄

时间:2018-07-15 03:18:59

标签: perl filehandle

脚本建议从ASCII文件中的某些数据表中提取一些值。

datatable

我修改了 script which I posted yesterday。 现在几乎行不通了。我想知道这是否是以这种方式移动文件句柄的正确方法。

用法仍然相同

myscript.pl targetfolder/*> result.csv

F是我的文件句柄。

我传递给子例程的参数是标量$_,它由if条件使用。当我想在子例程next if 1..4中向下移动时不起作用,因此我重复$a = <F>;几次以实现向下移动文件句柄。

但是我认为这不是在我的主代码和子例程中移动相同文件句柄的正确方法。我不确定它真的会贯穿每一行。我需要你的建议。

myscript.pl

#Report strip
use warnings;
use strict;

##Print the title 
Tfms2();

##Print the title 
print "\n";

@ff = <@ARGV>;

foreach $ff ( @ff ) {

    open (F, $ff);

    @fswf = @fschuck = @fsxpos = @fsypos = @fsdev = @csnom = ""; 
    @cswf = @cschuck = @csxpos = @csypos = @csnom = "";    # is there an efficient way?

    while (<F>) {
        Mfms2();
        Mfms3();
    }

    $r = 1;

    while ( $r <= $#fswf ) {      # because @fsws is the largest array
        Cfms3();   
        print "\n";
        $r++;
    }

    close (F);
}
##==========================================================================================
##Subs
##==========================================================================================

##FS II
sub Tfms2 {
    print "FS_Wafer,FS_ChuckID,FS_pos_X,FS_pos_Y,FS_deviation,CS_Wafer,CS_ChuckID,CS_pos_X,CS_pos_Y,CS_NofWafer_Ident_Spot";
}


sub Mfms2 {

    if ( /^F\sM\sSTATISTICS\sII$/ ) {

        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);

        $r = 1;

        @b = "";

        while ( $a !~ /\+\-/ ) {
            chomp $a;
            @b = split / *\| */, $a;

            $fswf[$r]    = $b[1];
            $fschuck[$r] = $b[2];
            $fsxpos[$r]  = $b[3];
            $fsypos[$r]  = $b[4];
            $fsdev[$r]   = $b[5];

            $r++;

            $a = (<F>);
            @b = "";
        }
    }
}


##FS III
sub Mfms3 {
    if ( /^F\sM\sSTATISTICS\sIII$/ ) {

        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);
        $a = (<F>);

        $r = 1;

        @b = "";

        while ( $a !~ /\+\-/ ) {
            chomp $a;
            @b = split / *\| */, $a;

            $cswf[$r]    = $b[1];
            $cschuck[$r] = $b[2];
            $csxpos[$r]  = $b[3];
            $csypos[$r]  = $b[4];
            $csnom[$r]   = $b[5];

            $r++;

            $a = (<F>);

            @b = "";
        }
    }
}


sub Cfms3 {
    print "$fswf[$r],$fschuck[$r],$fsxpos[$r],$fsypos[$r],$fsdev[$r],";
    print "$cswf[$r],$cschuck[$r],$csxpos[$r],$csypos[$r],$csnom[$r],";
}

1 个答案:

答案 0 :(得分:4)

您忘了告诉我们该程序应该做什么,因此很难获得任何帮助。您上一个问题中可能会有更多信息,但是我们在这里没有阅读所有问题,甚至没有包含上一个问题的链接。

您问题的答案是,您可以使用seek()移至文件中的任意位置。您可能会发现查看tell()很有用,它可以告诉您文件中当前的位置。

但是我认为信息对您没有特别的帮助,因为您似乎对自己的工作感到困惑。如果您要详细解释您的任务,那么我强烈怀疑我们可以为您提供帮助(并且我也怀疑,帮助很大程度上涉及从头开始重写代码)。但是,除非您提供详细信息,否则我们只能指出您的代码中一些更明显的问题。

  • 您应始终在代码中包含use strictuse warnings
  • 我认为@ff = <@ARGV>并没有您认为的那样。我认为您想要@ff = @ARGV代替。而且,即使那样,也感觉像是无意义地复制@ARGV
  • 具有相同名称的数组(@ff)和标量($ff)有时会使人感到困惑。而且,更一般而言,您需要付出更多的努力才能清楚地命名变量。
  • 请使用open()的三参数版本以及词汇文件句柄。您还应该始终检查open()-open my $fh, "<", $ff or die "Could not open $ff: $!"的返回码。
  • 您的@fswf=@fschuck=@fsxpos=@fsypos=@fsdev=@csnom=""之类的行并没有按照您认为的去做。您最终会得到很多数组,每个数组都包含一个元素。最好只用my声明数组-Perl会将它们创建为空(my (@fswf, @fschuck, @fsxpos, ...))。
  • 如果在读取文件时确实需要跳过八行,那么写起来就更加清晰了:$a = <F> for 1 .. 8
  • 您正在大量使用全局变量。有充分的理由说明这与软件工程的最佳实践相违背。它使您的代码比需要的脆弱得多。

总而言之,您似乎正在猜测这里的解决方案,但这绝不是一个好方法。正如我上面所说的,我们想为您提供帮助,但是如果没有更多信息,这几乎是不可能的。

更新:更仔细地查看代码,我发现您将从文件中解析出的数据存储在多个数组中。每个数组包含来自输​​入文件的单个列的数据,并且为了从单个行获取所有数据,您需要使用相同的索引值访问这些数组中的每个数组。这不是一个好主意。将链接数据拆分为不同的变量是灾难的根源。更好的主意是将每个记录存储在散列中(其中键表示存储的数据项),并将对所有这些散列的引用存储在数组中。这样会将所有数据整合到一个变量中。

更新后的更新:我不确定您的数据是否足够,但这是我要采取的那种方法。我只解析了数据,然后使用Data::Dumper显示了解析的数据结构。产生更好的输出留给读者练习:-)

#!/usr/bin/perl

use strict;
use warnings;
use feature 'say';

use Data::Dumper;

@ARGV or die "Usage: $0 file [file...]\n";

# Define two list of keys for the different types
my %cols = (
  II  => [qw(wf chuck xpos ypos dev)],
  III => [qw(wf chuck xpos ypos nom)],
);

my @data;     # To store the parsed data
my $cur_type; # Keep track of the current type of record

while (<>) {
  # Look for a record header and determine which type of 
  # record we're dealing with (I think 'II' or 'III').
  if (/^F M STATISTICS (III?)$/) {
    $cur_type = $1;
    next;
  }

  # Skip lines that are just headers/footers
  next if /\+[-=]/;
  # Skip lines that don't include data
  next unless /\d/;

  chomp;

  # Remove the start and end of the line
  s/^\|\s+//;
  s/\s+\|$//;

  # Store the data in a hash with the correct keys 
  # for this type of record
  my %rec;
  @rec{@{$cols{$cur_type}}} = split /\s+\|\s+/;

  # Store a reference to our hash in @data
  push @data, \%rec;
}

# Dump the contents of @data
say Dumper \@data;