我可以同时读取和写入多个文件句柄(Perl)吗?

发布于 2024-07-29 00:00:07 字数 3169 浏览 3 评论 0原文

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

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

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

每个变量都被声明并具有我想要的值。

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


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

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

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

感谢任何帮助。

I'm trying to read from two files, and generate output in a third. I first wanted to edit the first one on the go but I didn't find a suitable method save for arrays.

My problem is that the third file (output) is empty whenever I uncomment the "_ref_param_handling" function. BUT the following is what puzzles me the most: If I do a UNIX very basic `cat` system call on the output file at then end (see code below), it works just fine. If I open the filehandle just before and close it right after editing, it also works fine (around my print FILEHANDLE LIST).

I undoubtedly am missing something here. Apart from a problem between my keyboard and my chair, what is it? A filehandle conflict? A scope problem?

Every variable is declared and has the value I want it to have.

Edit (not applicable anymore).
Using IO::File on the three files didn't change anything.


Edit 2 : New full subroutine code

My code works (except when my ref already exists, but that's because of the "append" mode i think) but there might be some mistakes and unperlish ways of coding (sorry, Monks). I, however, use Strict and warnings !

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  

the _ref_param_handle subroutine still is :

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;
}

Extract from manda_def file :

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   .+

Extract from 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

Any help appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

尽揽少女心 2024-08-05 00:00:07

目前还不清楚什么是初始化 $refhandle$newrefhandle$mde。 根据它们所具有的值将影响 open 的行为 - 即是否会在打开新文件句柄之前关闭任何文件句柄。

我建议您开始使用 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;
    }
}

It is unclear what is initialising $refhandle, $newrefhandle and $mde. Depending on the values they have will affect the behaviour of open - i.e. whether it will close any filehandles before opening a new one.

I would suggest that you start using the IO::File interface to open/write to files, as this makes the job of filehandle management much easier, and will avoid any inadvertent closes. Something like...

use IO::File;

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

$refhandle->print(...);

As far as editing files in place goes, this is a common pattern I use to achieve this, make sure of the -i behaviour of perl.

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;
    }
}
谈场末日恋爱 2024-08-05 00:00:07

尝试打开第二个文件句柄以在循环外进行输入,并传递对子例程 _ref_param_handle 的引用。使用查找函数来查找文件以重新开始。
如果您的文件不太大,您还可以考虑将内容存储在数组并访问它而不是循环访问相同的内容。
编辑:

这是一个小例子来支持我上面想说的内容:


#!/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 参考

try opening the second file handle for input outside the loop and pass a reference to the subroutine _ref_param_handle.Use seek function to seek file back to start.
If your file is not too large you can also think of storing the content in an array and the accessing it instead of looping over same contents.
EDIT:

Here is a small example to support what I was trying to say above:


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

Info about perl references

情泪▽动烟 2024-08-05 00:00:07

根据我收集的信息,您的脚本想要将以下形式的文件转换为:

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');

From what I gather, your script wants to convert a file in the following form:

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

to something like this:

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

The following works. I don't know what manda_def means, and also I didn't bother to create an actual variable replacement function.

#!/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');
梦在夏天 2024-08-05 00:00:07

伙计们,我认真考虑用我的无线鼠标上吊自杀。

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

/me *cries*

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

Guys, I seriously consider hanging myself with my wireless mouse.

My script never failed. I just didn't ran it through the end (it's actually a very long parameter list). The printing is just done as soon as the filehandle is closed (or so I guessed)...

/me *cries*

I've spent 24 hours on this...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文