在Perl模块中打开文件的位置

时间:2017-12-08 11:00:14

标签: perl module file-handling

以下是我正在编写的模块的玩具版本。这个例子忠实地展示了我遇到的问题。

我有一个文件bed_in.txt

2L      0       4953
2L      16204   16284
2L      16612   16805
2L      17086   18561
2L      18757   18758
2L      19040   19120
2L      19445   19635
2L      19894   21366
2L      21582   21583
2L      47501   52365
2L      4698700 4709369

我想用来过滤数组中的值。

我想检查bed_in.txt的第二列是否与

中的任何值匹配
my @lines = qw/ 16204 40 200 149 19445 178 /;

如果是这样,将推送到数组。

此数据的最终输出应该是@lines中同样位于bed_in.txt

第二列的两个元素
2L      0       4953
2L      16204   16284 # 16204 == 16204
2L      16612   16805
2L      17086   18561
2L      18757   18758
2L      19040   19120
2L      19445   19635 # 19445 == 19445

但我应该在哪里打开文件?

是否应该在调用模块run_fileOpen.pl的脚本中或模块本身中发生这种情况?

在任何一种情况下,我都没有得到正确的输出,我的模块似乎只被调用@lines的第一个元素

parseFile.pm

#!/usr/bin/perl

package parseFile;
use strict;
use warnings;

use FindBin qw/ $Bin /;
use lib File::Spec->catdir($FindBin::Bin, '..', 'bin/');

use Data::Printer;

open my $bed, '<', 'bed_in.txt';

sub check_lines {
  my ($line, $filter_ref) = @_;
  my @filter_reasons = @{ $filter_ref };

  my $lines_to_filter_ref = filter_lines($line, $bed, \@filter_reasons);

  return($lines_to_filter_ref);
}


sub filter_lines {
  my ($line, $bed_file, $lines_to_filter) = @_;

  my @filter = @{ $lines_to_filter };

  while(<$bed_file>){
    chomp;
    my $start = (split)[1];
    # print "line: $line  start: $start\n";
    if ($line == $start ) {

      push @filter, "Filter as equal: $start, $line [$_]";
    }
  }
  # p(@filter);
  return(\@filter);
}


1;

run_parseFile.pl

#!/usr/bin/perl

use strict;
use warnings;

use parseFile;


my @lines = qw/ 16204 40 200 149 19445 178 /;

foreach(@lines){
  my @filter_reasons = 'reason 1';
  my $lines2filter = parseFile::check_lines($_, \@filter_reasons);
  @filter_reasons = @{ $lines2filter };
  print "$_\n" foreach @filter_reasons;
}

输出

reason 1
Filter as equal: 16204, 16204 [2L   16204   16284]
reason 1
reason 1
reason 1
reason 1
reason 1

当我向print中的while循环添加filter_lines语句时,我可以看到只有第一个元素正在运行:

line: 16204  start: 0
line: 16204  start: 16204
line: 16204  start: 16612
line: 16204  start: 17086
line: 16204  start: 18757
line: 16204  start: 19040
line: 16204  start: 19445
line: 16204  start: 19894
line: 16204  start: 21582
line: 16204  start: 47501
line: 16204  start: 4698700

这是处理打开bed_in.txt文件的合适方式,还是应该在run_parseFile.pl脚本中打开它?或者我的代码还有其他问题吗?

2 个答案:

答案 0 :(得分:1)

以下是我写这个的方法。正如我所说,我更喜欢面向对象的解决方案

new构造函数需要文件名作为参数。它打开文件,将信息读入哈希,并祝福制作对象

唯一的方法是check_lines,它需要一个值和一个原因字符串。它只是询问给定值的哈希值,并根据值是否找到返回一个或两个元素的数组

最好限制此对象的范围,否则哈希将在需要后保留在内存中。所以我已经将所有需要该对象的操作包含在一个块中。当对象在块结束时超出范围时,它将被自动销毁

BedInFilter.pm

package BedInFilter;

use strict;
use warnings 'all';

use Carp 'croak';

sub new {
    my $class = shift;
    my ( $bed_file ) = @_;

    my %self;

    open my $fh, '<', $bed_file
            or croak qq{Unable to open "$bed_file" for input: $!};

    while ( <$fh> ) {

        next unless /\S/;
        chomp;

        my $val = ( split )[1];
        $self{$val} = $_;
    }

    bless \%self, $class;
}

sub check_lines {
    my $self = shift;
    my ( $val, $reason ) = @_;

    my $result = [ $reason ];

    my $line = $self->{$val};

    push @$result, "Filter as equal: $val, $val [$line]" if $line;

    $result;
}

1;

bed_in.pl

use strict;
use warnings 'all';

use BedInFilter;

my @values = qw/ 16204 40 200 149 19445 178 /;

{
    my $filter = BedInFilter->new( 'bed_in.txt' );

    for my $val ( @values ) {

        my $reason = 'reason1';

        my $result = $filter->check_lines( $val, $reason );

        print "@$result\n";
    }
}

输出

reason1 Filter as equal: 16204, 16204 [2L      16204   16284]
reason1
reason1
reason1
reason1 Filter as equal: 19445, 19445 [2L      19445   19635]
reason1

答案 1 :(得分:0)

模块应该打开和关闭同一子程序中的文件,除非子的名称中有“open”,在这种情况下,它应该返回一个文件句柄作为其返回值之一。并且应该有一个相应的“关闭”子匹配每个“开放”子。