加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

perl – 如何将文件句柄传递给函数?

发布时间:2020-12-15 23:26:43 所属栏目:大数据 来源:网络整理
导读:当我运行下面的代码时,我得到了 Can't use string ("F") as a symbol ref while "strict refs" in use at ./T.pl line 21. 第21行是 flock($fh,LOCK_EX); 我究竟做错了什么? #!/usr/bin/perluse strict;use warnings;use Fcntl ':flock','SEEK_SET'; # file
当我运行下面的代码时,我得到了

Can't use string ("F") as a symbol ref while "strict refs" in use at ./T.pl line 21.

第21行是

flock($fh,LOCK_EX);

我究竟做错了什么?

#!/usr/bin/perl

use strict;
use warnings;
use Fcntl ':flock','SEEK_SET'; # file locking
use Data::Dumper;
# use xx;

my $file = "T.yaml";
my $fh = "F";
my $obj = open_yaml_with_lock($file,$fh);

$obj->{a} = 1;

write_yaml_with_lock($obj,$fh);

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

    open $fh,'+<',$file;
    flock($fh,LOCK_EX);
    my $obj = YAML::Syck::LoadFile($fh);

    return $obj;
}

sub write_yaml_with_lock {
    my ($obj,$fh) = @_;

    my $yaml = YAML::Syck::Dump($obj);
    $YAML::Syck::ImplicitUnicode = 1;
    seek $fh,SEEK_SET;   # seek back to the beginning of file

    print $fh $yaml . "---n";
    close $fh;
}

解决方法

你做错了是使用字符串“F”作为文件句柄.这个
从来没有像这样的东西;你可以用一个裸字作为
filehandle(打开FH,……;打印FH …),或者你可以传入
空标量和perl会为其分配一个新的打开文件对象
变量.但是如果你传入字符串F,那么你需要参考
然后处理为F,而不是$fh.但是,不要这样做.

改为:

sub open_yaml_with_lock {
    my ($file) = @_;

    open my $fh,$file or die $!;
    flock($fh,LOCK_EX) or die $!;

    my $obj = YAML::Syck::LoadFile($fh); # this dies on failure
    return ($obj,$fh);
}

我们在这里做了几件事.一,我们不存储
全局中的文件句柄.全球州使您的计划非常出色
难以理解 – 我的10行帖子很难 –
应该避免.如果你愿意,只需返回文件句柄即可
保持它.或者,您可以像打开一样对其进行别名:

sub open_yaml_with_lock {
    open $_[0],$_[1] or die $!;
    ...
}

open_yaml_with_lock(my $fh,'filename');
write_yaml_with_lock($fh);

但实际上,这是一团糟.把这些东西放在一个物体里.造新
打开并锁定文件.添加写入方法.完成.现在你可以
重用这段代码(并让其他人做同样的事情)而不用担心
弄错了.更少的压力.

我们在这里做的另一件事是检查错误.是的,磁盘可以
失败.文件可能被拼写错误.如果你幸福地忽略了返回值
开放和群集,然后你的程序可能没有做你的想法
它正在做.该文件可能无法打开.该文件可能不是
锁定得当.有一天,你的程序无法正常工作
因为你拼写“文件”为“flie”并且文件无法打开.
几个小时你会抓挠头脑,想知道发生了什么.
最终,你会放弃,回家,稍后再试.这次,
你不会错误地输入文件名,它会起作用.几个小时会
被浪费了.你会比你应该早几年死去
因为累积的压力.所以只需使用autodie或写或
死!系统调用后,以便在收到错误消息时
出了点问题!

如果您使用autodie qw / open flock编写脚本将是正确的
寻求关闭/在顶部. (实际上,你也应该检查一下
工作或使用“打印”
File::Slurp或
syswrite,因为autodie无法检测到失败的print语句.)

无论如何,总结一下:

>定义$fh时不要打开$fh.写下我的$fh给
??避免考虑这个.
>始终检查系统调用的返回值.让autodie做
??这个给你.
>不要保持全球状态.不要写一堆函数
??意图是一起使用,但依赖于隐含的先决条件
??像一个打开的文件.如果函数有前置条件,请将它们放入
??一个类并使构造函数满足前提条件.
??这样,你就不会意外地写出错误的代码!

更新

好的,这是如何使这更多的OO.首先,我们将做“纯Perl”OO
然后使用Moose.麋是
我将用于任何实际工作; “纯粹的Perl”只是为了
为了让那些对OO和OO都不熟悉的人容易理解
Perl的.

package LockedYAML;
use strict;
use warnings;

use Fcntl ':flock','SEEK_SET';
use YAML::Syck;

use autodie qw/open flock sysseek syswrite/;

sub new {
    my ($class,$filename) = @_;
    open my $fh,$filename;
    flock $fh,LOCK_EX;

    my $self = { obj => YAML::Syck::LoadFile($fh),fh => $fh };
    bless $self,$class;
    return $self;
}

sub object { $_[0]->{obj} }

sub write {
    my ($self,$obj) = @_;
    my $yaml = YAML::Syck::Dump($obj);

    local $YAML::Syck::ImplicitUnicode = 1; # ensure that this is
                                            # set for us only

    my $fh = $self->{fh};

    # use system seek/write to ensure this really does what we
    # mean.  optional.
    sysseek $fh,SEEK_SET;
    syswrite $fh,$yaml;

    $self->{obj} = $obj; # to keep things consistent
}

然后,我们可以在主程序中使用该类:

use LockedYAML;

my $resource = LockedYAML->new('filename');
print "Our object looks like: ". Dumper($resource->object);

$resource->write({ new => 'stuff' });

错误将抛出异常,可以使用
Try::Tiny,和YAML
只要实例存在,文件就会保持锁定状态.你可以
当然,一次有很多LockedYAML对象,这就是我们的原因
做到了OO.

最后,穆斯版本:

package LockedYAML;
use Moose;

use autodie qw/flock sysseek syswrite/;

use MooseX::Types::Path::Class qw(File);

has 'file' => (
    is       => 'ro',isa      => File,handles  => ['open'],required => 1,coerce   => 1,);

has 'fh' => (
    is         => 'ro',isa        => 'GlobRef',lazy_build => 1,);

has 'obj' => (
    is         => 'rw',isa        => 'HashRef',# or ArrayRef or ArrayRef|HashRef,or whatever
    lazy_build => 1,trigger    => sub { shift->_update_obj(@_) },);

sub _build_fh {
    my $self = shift;
    my $fh = $self->open('rw');
    flock $fh,LOCK_EX;
    return $fh;
}

sub _build_obj {
    my $self = shift;
    return YAML::Syck::LoadFile($self->fh);
}

sub _update_obj {
    my ($self,$new,$old) = @_;
    return unless $old; # only run if we are replacing something

    my $yaml = YAML::Syck::Dump($new);

    local $YAML::Syck::ImplicitUnicode = 1;

    my $fh = $self->fh;
    sysseek $fh,$yaml;

    return;
}

这类似地使用:

use LockedYAML;

 my $resource = LockedYAML->new( file => 'filename' );
 $resource->obj; # the object
 $resource->obj( { new => 'object' }); # automatically saved to disk

Moose版本更长,但运行时一致性更高检查并且更容易增强.因人而异.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读