【问题标题】:Can I read and write to multiple filehandles simultaneously (Perl)?我可以同时读取和写入多个文件句柄(Perl)吗?
【发布时间】:2009-07-29 08:03:03
【问题描述】:

我正在尝试从两个文件中读取,并在第三个文件中生成输出。我首先想在旅途中编辑第一个,但我没有找到合适的方法来保存数组。

我的问题是,每当我取消注释“_ref_param_handling”函数时,第三个文件(输出)都是空的。 但是以下是最让我困惑的:如果我在最后的输出文件上执行一个非常基本的 UNIX `cat` 系统调用(见下面的代码),它工作得很好。如果我在之前打开文件句柄并在编辑后立即关闭它,它也可以正常工作(围绕我的 print FILEHANDLE LIST)。

我无疑在这里遗漏了一些东西。除了我的键盘和椅子之间的问题之外,还有什么问题?文件句柄冲突?范围问题?

每个变量都被声明并具有我希望它具有的值。

编辑(不再适用)。 在三个文件上使用 IO::File 并没有改变任何东西。


编辑2:新的完整子程序代码

我的代码可以工作(除非我的 ref 已经存在,但那是因为我认为是“附加”模式),但可能存在一些错误和 unperlish 编码方式(抱歉,Monks)。但是,我使用严格和警告

sub _ref_edit($) {
    my $manda_def = "$dir/manda_def.list";
    my $newrefhandle;
    my $ref       = $_[0];
    (my $refout   = $ref) =~ s/empty//;
    my $refhandle;
    my $parname   = '';
    my $parvalue  = '';
    my @val;

    _printMan;

    my $flush = readline STDIN;    # Wait for <enter>

    # If one or both of the ref. and the default values are missing
    if ( !( -e $manda_def && -e $ref ) ) {
        die "Cannot find $ref and/or $manda_def";
    }

    # Open needed files (ref & default)
    open( $refhandle, "<", $ref ) or die "Cannot open ref $ref : $!";
    open( $newrefhandle, ">>", $refout ) 
      or die "Cannot open new ref $refout : $!";

    # Read each line
    while ( my $refline = <$refhandle> ) {
    # If line read not an editable macro
        if ( $refline =~ /^define\({{(.+)}},\s+{{.*__VALUE__.*}}\)/ ){
        $parname = $1;         # $1 = parameter name captured in regexp
        # Prompt user
        $parvalue = _ref_param_handling( $parname, $manda_def );   
        # Substitution in ref
        $refline =~ s/__VALUE__/$parvalue/;
        # Param not specified and no default value
        $parvalue eq '' ? $refline=~s/__COM__/#/ : $refline=~s/__COM__//; 
        }

    print $newrefhandle $refline;
    }
    close $newrefhandle;
    close $refhandle;

    return $refout;
}    # End ref edit  

_ref_param_handle 子程序还是:

open( $mde, '<', $_[1] )
      or die "Cannot open mandatory/default list $_[1] : $!";

    # Read default/mandatory file list 
    while (<$mde>) {       
       ( $name, $manda, $default, $match, $descript ) = split( /\s+/, $_, 5 ); 
       next if ( $name !~ $ref_param );  # If param read differs from parname

    (SOME IF/ELSE)

    } # End while <MDE>
    close $mde;
    return $input;
}

从 manda_def 文件中提取:

NAME  Mandatory? Default Match      Comm.
PORT          y NULL  ^\d+$ Database port
PROJECT       y NULL  \w{1,5}   Project name
SERVER        y NULL  \w+           Server name
modemRouting  n NULL  .+        
modlib        y bin   .+        
modules       y sms   .+

从 ref_file 中提取:

define({{PORT}},         {{__VALUE__}})dnl
define({{PROJECT}},      {{__VALUE__}})dnl
define({{SERVER}},       {{__VALUE__}})dnl
define({{modemRouting}}, {{__COM__{{$0}} '__VALUE__'}})dnl
define({{modlib}},       {{__COM__{{$0}} '__VALUE__'}})dnl
define({{modules}},      {{__COM__{{$0}} '__VALUE__'}})dnl

任何帮助表示赞赏。

【问题讨论】:

  • 始终使用“use strict;”和“use warnings'”启动您的 Perl 程序。
  • 我愿意!这只是子程序的一部分。
  • 认为我明白你的意思。仍然不知道您是否想要替换所有这些 {{}},想。无论如何,您说这已经有效,除了“>>”?你得到什么错误?
  • 嗨莱昂纳多,感谢您的回复。我不想替换我的任何{{' or }}',它们是我的 m4 注释分隔符。当使用“>>”访问现有的 ref_file 时,我实际上得到了一个无限的写入循环,但不要在这上面浪费时间。我正在调用 $EDITOR(或 vi)而不是逐行提示(仅在指定现有 ref_file 时)。这样,用户可以修改任何他需要的内容。

标签: perl filehandle


【解决方案1】:

目前尚不清楚正在初始化 $refhandle$newrefhandle$mde。取决于它们的值会影响打开的行为 - 即它是否会在打开新文件句柄之前关闭任何文件句柄。

我建议您开始使用IO::File 接口来打开/写入文件,因为这使文件句柄管理工作变得更加容易,并且可以避免任何意外关闭。比如……

use IO::File;

my $refhandle = IO::File->new("< $ref") or die "open() - $!";

$refhandle->print(...);

就就地编辑文件而言,这是我用来实现此目的的常用模式,请确保 perl 的 -i 行为。

sub edit_file
{
    my ($filename) = @_;

    # you can re-create the one-liner above by localizing @ARGV as the list of
    # files the <> will process, and localizing $^I as the name of the backup file.
    local (@ARGV) = ($filename);
    local($^I) = '.bak';

    while (<>)
    {
        s/original string/new string/g;
    }
    continue
    {
        print;
    }
}

【讨论】:

  • 好的,谢谢。幸运的是,IO::File 似乎包含在 Perl 的标准交付中(我可能不会在我将使用的机器上安装任何软件包)。关于我的三个变量,它们只是被声明为“my _;”。这很糟糕吗?
  • IO::File 似乎没有改变任何东西(见第一篇文章编辑):(
  • 像我一样声明文件句柄还不错 - 根据文档,未定义的标量变量被分配了对新匿名文件句柄的引用。
【解决方案2】:

尝试在循环外打开第二个文件句柄以供输入,并传递对子例程 _ref_param_handle 的引用。使用 seek 函数重新开始寻找文件。
如果您的文件不是太大,您也可以考虑存储数组中的内容和访问它而不是循环遍历相同的内容。
编辑:
这是一个小例子来支持我上面所说的:


#!/usr/bin/perl -w

sub test
{
 my $fh_to_read = $_[0] ;
 my $fh_to_write = $_[1] ;

 while(<$fh_to_read>)
 {
  print $fh_to_write  $_ ;
 }
 seek($fh_to_read,0,0) ;
}

open(FH1,"<dummy1");
open(FH2,"<dummy2");
open(FH3,">dummy3");

while(<FH2>)
{
 print FH3 "$_" ;
 test(\*FH1,\*FH3);
}

关于perl references的信息

【讨论】:

  • 感谢您的回答。我不熟悉 perl 的引用(很难将 C++ 的指针/引用与 Perl 的硬/软引用区分开来)。我尝试了 _ref_param_handling($\$) 但将 \$mde 传递给我的函数会返回错误。有没有技巧(或解释...... :))
【解决方案3】:

据我所知,您的脚本希望将文件转换为以下形式:

define({{VAR1}}, {{__VALUE__}})
define({{VAR2}}, {{__VALUE__}})
define({{VAR3}}, {{__VALUE__}})
define({{VAR4}}, {{__VALUE__}})

到这样的事情:

define({{VAR1}}, {{}})
define({{VAR2}}, {{VALUE2}})
define({{VAR3}}, {{VALUE3}})
define({{VAR4}}, {{}})

以下作品。我不知道 manda_def 是什么意思,也懒得去创建一个实际的变量替换函数。

#!/usr/bin/perl
use strict;
use warnings;

sub work {
    my ($ref, $newref, $manda_def) = @_;

    # Open needed files (ref & default)
    open(my $refhandle, '<', $ref) or die "Cannot open ref $ref : $!";
    open(my $newrefhandle, '>', $newref) or die "Cannot open new ref $newref: $!";

    # Read each line
    while (my $refline = <$refhandle>) {
        # if line read is not an editable macro
        if ($refline =~ /^define\({{(.+)}},\s+{{.*__VALUE__.*}}\)/){
            my $parvalue = _ref_param_handling($1, $manda_def); # manda_def?
            # Substitution in ref
            $refline  =~ s/__VALUE__/$parvalue/;
            # Param not specified and no default value
            $refline  =~ s/__COM__/#/ if $parvalue eq '';
        }
        print $newrefhandle $refline;
    }
    close $newrefhandle;
    close $refhandle;

    return $newref;
}

sub _ref_param_handling {
    my %parms = (VAR2 => 'VALUE2', VAR3 => 'VALUE3');
    return $parms{$_[0]} if exists $parms{$_[0]};
}

work('ref.txt', 'newref.txt', 'manda.txt');

【讨论】:

  • 事实上它比这复杂一点。 $manda_def 是一个文件路径,其中包含参数的默认值列表,说明它们是否是强制性的,并为以后的用户输入提供匹配模式。 _ref_param_handling *通过另一个while/filehandle打开这个文件(我认为它与其他两个冲突)并要求用户输入参数。如果您仍然想提供帮助,我将在明天早上发布更多示例;)
  • 两件事。如果您根据任何答案修复了程序,则应将其标记为此类。其次,您认为首先是什么导致了您的问题?
  • 不,我当时没有修复任何东西,我只是发布了整个代码。正如我所说,我的脚本从未失败,写作只是在最后完成(当“关闭”发生时);)我的问题有点解决了。
  • 哦——你的意思是你只是想在执行过程中检查你的进度吗?然后你应该冲洗你的把手。更简单的方法是在脚本开头添加“$| = 1”。
  • 对不起,我之前没有看到你们的 cmets,但是,是的,这基本上就是我想做的!谢谢!
【解决方案4】:

伙计们,我认真考虑用无线鼠标吊死自己。

我的脚本从未失败。我只是没有跑完它(它实际上是一个很长的参数列表)。文件句柄关闭后打印就完成了(或者我猜的)...

/我*哭泣*

我在这上面花了 24 小时...

【讨论】:

  • Isaac,你能把实际的代码投入使用吗?不是简化的 sn-p,而是整个功能。我认为您的问题发生在其他地方。您是否在程序顶部放置了“使用严格”和“使用警告”?您是否使用小范围的变量?此外,您的“ref”文件的一个小样本将对您有所帮助。
  • 不要对自己太苛刻——我们都做到了........只是不要再这样做了 8-)!!!
  • 我会在早上的第一个小时发布所有内容,我现在不在我的开发计算机旁。当然,我使用警告和严格。没有它们,Perl 太棘手了。关于范围,我一直在使用 my(只有“我们的”变量用于 GetOpts::Std),即使当我在网络和/或 Perl 书籍上阅读它时有时会让我感到困惑.
  • 也许您可以更新问题以说明这一点。不过,这并不是你有过的不寻常的经历。 :)
猜你喜欢
  • 2014-06-17
  • 2020-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-14
  • 1970-01-01
  • 2013-10-18
相关资源
最近更新 更多