Return 来自子程序的文件句柄并传递给其他子程序

Return file handle from subroutine and pass to other subroutine

我正在尝试创建几个可以协同工作的函数。 getFH 应该采用打开文件的模式( >< ),然后是文件本身(从命令行)。它应该做一些检查以查看文件是否可以打开,然后打开它,然后 return 文件句柄。 doSomething 应该接受文件句柄,循环数据并做任何事情。但是,当程序进入 while 循环时,出现错误:

readline() on unopened filehandle 1

我在这里做错了什么?

#! /usr/bin/perl

use warnings;
use strict;
use feature qw(say);

use Getopt::Long;
use Pod::Usage;

# command line param(s)
my $infile = '';
my $usage = "\n\n[=11=] [options] \n
Options
-infile         Infile
-help           Show this help message
\n";

# check flags
GetOptions(
    'infile=s' => $infile,
    help       => sub { pod2usage($usage) },
) or pod2usage(2);

my $inFH = getFh('<', $infile);

doSomething($inFH);

## Subroutines ##

## getFH ##
## @params:
## How to open file: '<' or '>'
## File to open

sub getFh {
    my ($read_or_write, $file) = @_;
    my $fh;

    if ( ! defined $read_or_write ) {
        die "Read or Write symbol not provided", $!;
    }

    if ( ! defined $file ) {
        die "File not provided", $!;
    }

    unless ( -e -f -r -w $file ) {
        die "File $file not suitable to use", $!;
    }

    unless ( open( $fh, $read_or_write, $file ) ) {
        die "Cannot open $file",$!;
    }

    return($fh);
}

#Take in filehandle and do something with data

sub doSomething{
    my $fh = @_;

    while ( <$fh> ) {
        say $_;
    }
}
my $fh = @_;

这一行并不代表你认为的意思。它将 $fh 设置为 @_ 中的项目数,而不是传入的文件句柄 - 如果您打印 $fh 的值,它将是 1 而不是文件句柄。

请改用 my $fh = shiftmy $fh = $_[0]my ($fh) = @_

如前所述,my $fh = @_ 会将 $fh 设置为 1,这不是文件句柄。使用

my ($fh) = @_

改为使用列表赋值

另外

  • -e -f -r -w $file不会如你所愿。你需要

    -e $file and -f $file and -r $file and -w $file
    

    你可以通过使用下划线 _ 代替文件名来使它更简洁和高效,这将重新使用为之前的文件测试

    获取的信息
    -e $file and -f _ and -r _ and -w _
    

    但是,请注意,如果文件不是 可写,您将拒绝请求,如果请求是打开文件进行读取,则没有任何意义。此外,如果文件不存在,-f 将 return false,因此 -e 是多余的

  • 最好在 die 字符串中包含 $!,因为它包含失败的 原因,但您的第一个两个测试没有设置这个值,所以应该只是 die "Read or Write symbol not provided";

    另外,die "Cannot open $file", $!应该是

    die qq{Cannot open "$file": $!}
    

    明确文件名是否为空,并在消息和$!

  • 的值之间添加一些space
  • 从文件中读取的行最后会有一个换行符,所以不需要say。只需 print while <$fh> 即可

  • Perl 变量名通常是snake_case,所以get_fhdo_something更常见