如何在Perl模块中包含数据文件?

如何在Perl模块中包含数据文件?,perl,perl-module,directory-structure,data-files,Perl,Perl Module,Directory Structure,Data Files,将运行时所需的数据文件与Perl模块捆绑在一起的“正确”方式是什么,以便该模块可以在使用前读取其内容 一个简单的例子是这个Dictionary模块,它需要在启动时读取(单词、定义)对的列表 package Reference::Dictionary; # TODO: This is the Dictionary, which needs to be populated from # data-file BEFORE calling Lookup! our %Dictionary; sub

将运行时所需的数据文件与Perl模块捆绑在一起的“正确”方式是什么,以便该模块可以在使用前读取其内容

一个简单的例子是这个Dictionary模块,它需要在启动时读取(单词、定义)对的列表

package Reference::Dictionary;

# TODO: This is the Dictionary, which needs to be populated from
#  data-file BEFORE calling Lookup!
our %Dictionary;

sub new {
  my $class = shift;
  return bless {}, $class;
}

sub Lookup {
  my ($self,$word) = @_;
  return $Dictionary{$word};
}
1;
和一个驱动程序Main.pl:

use Reference::Dictionary;

my $dictionary = new Reference::Dictionary;
print $dictionary->Lookup("aardvark");
现在,我的目录结构如下所示:

root/
  Main.pl
  Reference/
    Dictionary.pm
    Dictionary.txt
我似乎无法让Dictionary.pm在启动时加载Dictionary.txt。我已经尝试了一些方法来实现这一点,比如

  • 使用开始块:

    BEGIN {
      open(FP, '<', 'Dictionary.txt') or die "Can't open: $!\n";
      while (<FP>) {
        chomp;
        my ($word, $def) = split(/,/);
        $Dictionary{$word} = $def;
      }
      close(FP);
    }
    
    这也会失败,因为BEGIN在编译时执行,在数据可用之前执行

  • 硬编码模块中的数据

    our %Dictionary = (
      aardvark => 'an animal which is definitely not an anteater',
      abacus => 'an oldschool calculator'
      ...
    );
    
    工作正常,但绝对不可维护


这里有一个类似的问题:但它涉及的是由CPAN安装的模块,而不是像我试图做的那样与当前脚本相关的模块。

没有必要在
开始时加载字典<代码>开始
时间与正在加载的文件有关。当您的
main.pl
use Dictionary
时,Dictionary.pm中的所有代码都被编译和加载。将代码提前加载到Dictionary.pm

package Dictionary;

use strict;
use warnings;

my %Dictionary;  # There is no need for a global
while (<DATA>) {
    chomp;
    my ($word, $def) = split(/,/);
    $Dictionary{$word} = $def;
}
你应该用哪一种<代码>数据更易于分发。一个独立的并行文件对于非编码人员来说更容易处理


与在加载库时加载整个词典相比,在需要时等待加载词典更为礼貌

use File::Basename;

# Load the dictionary from Dictionary.txt
sub _load_dictionary {
    my %dictionary;

    # Get the directory Dictionary.pm is located in.
    my $dir = dirname(__FILE__);

    open(my $fh, '<', "$dir/Dictionary.txt") or die "Can't open: $!\n";

    while (<$fh>) {
        chomp;
        my ($word, $def) = split(/,/);
        $dictionary{$word} = $def;
    }

    return \%dictionary;
}

# Get the possibly cached dictionary
my $Dictionary;
sub _get_dictionary {
    return $Dictionary ||= _load_dictionary;
}

sub new {
    my $class = shift;

    my $self = bless {}, $class;
    $self->{dictionary} = $self->_get_dictionary;

    return $self;
}

sub lookup {
    my $self = shift;
    my $word = shift;

    return $self->{dictionary}{$word};
}
使用File::Basename;
#从dictionary.txt加载字典
子加载字典{
我的字典;
#获取Dictionary.pm位于的目录。
my$dir=dirname(_文件__);

open(my$fh),我建议使用
DATA
with,以确保在运行时之前对数据进行初始化。这也使其更易于自我记录

或者更适合使用
UNITCHECK
块,该块将在库文件编译后立即尽早执行,因此可以被视为编译的扩展

package Dictionary;

use strict;
use warnings;

my %dictionary;
UNITCHECK {
    while ( <DATA> ) {
        chomp;
        my ($k, $v) = split /,/;
        $dictionary{$k} = $v;
    }
}
包字典;
严格使用;
使用警告;
我的字典;
单位支票{
而(){
咀嚼;
我的($k,$v)=分割/,/;
$dictionary{$k}=$v;
}
}

请注意原型(即
sub-new()
)除非你知道你在做什么,否则不要使用它们。如果你想让函数签名考虑,或者,我建议使用<代码>数据< /代码>用<代码> init <代码>,而不是<代码>开始<代码>,以确保数据在运行前被初始化。documenting@Schwern oops我的错,最近C/C++太多了!我将进行编辑以删除它们。您还应该避免在方法标识符中使用大写字母。它们是为Perl全局变量(如包名)保留的,因此您的
子查找
应该是
子查找
@Borodin大写方法名称没有保留。这不是正常的Perl样式,但它们是没有保留。
use File::Basename;

# Get the directory Dictionary.pm is located in.
my $dir = dirname(__FILE__);

open(my $fh, '<', "$dir/Dictionary.txt") or die "Can't open: $!\n";

my %Dictionary;
while (<$fh>) {
    chomp;
    my ($word, $def) = split(/,/);
    $Dictionary{$word} = $def;
}
close($fh);
use File::Basename;

# Load the dictionary from Dictionary.txt
sub _load_dictionary {
    my %dictionary;

    # Get the directory Dictionary.pm is located in.
    my $dir = dirname(__FILE__);

    open(my $fh, '<', "$dir/Dictionary.txt") or die "Can't open: $!\n";

    while (<$fh>) {
        chomp;
        my ($word, $def) = split(/,/);
        $dictionary{$word} = $def;
    }

    return \%dictionary;
}

# Get the possibly cached dictionary
my $Dictionary;
sub _get_dictionary {
    return $Dictionary ||= _load_dictionary;
}

sub new {
    my $class = shift;

    my $self = bless {}, $class;
    $self->{dictionary} = $self->_get_dictionary;

    return $self;
}

sub lookup {
    my $self = shift;
    my $word = shift;

    return $self->{dictionary}{$word};
}
package Dictionary;

use strict;
use warnings;

my %dictionary;
UNITCHECK {
    while ( <DATA> ) {
        chomp;
        my ($k, $v) = split /,/;
        $dictionary{$k} = $v;
    }
}