如何使用 Perl 模块包含数据文件?
How to include a data file with a Perl module?
将运行时所需的数据文件与 Perl 模块捆绑在一起的 "proper" 方法是什么,以便模块可以在使用前读取其内容?
一个简单的例子就是这个字典模块,它需要在启动时读取(单词,定义)对列表。
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 块:
BEGIN {
open(FP, '<', 'Dictionary.txt') or die "Can't open: $!\n";
while (<FP>) {
chomp;
my ($word, $def) = split(/,/);
$Dictionary{$word} = $def;
}
close(FP);
}
没有骰子:Perl 正在 cwd 中查找 Dictionary.txt,这是主脚本 ("Main.pl") 的路径,而不是模块的路径,所以这给出了文件未找到。
使用数据:
BEGIN {
while (<DATA>) {
chomp;
my ($word, $def) = split(/,/);
$Dictionary{$word} = $def;
}
close(DATA);
}
并在模块结束时
__DATA__
aardvark,an animal which is definitely not an anteater
abacus,an oldschool calculator
...
这也失败了,因为 BEGIN 在编译时执行,在 DATA 可用之前。
硬编码模块中的数据
our %Dictionary = (
aardvark => 'an animal which is definitely not an anteater',
abacus => 'an oldschool calculator'
...
);
有效,但绝对不可维护。
这里有类似的问题:How should I distribute data files with Perl modules?但是那个问题涉及 CPAN 安装的模块,而不是我正在尝试做的与当前脚本相关的模块。
无需在 BEGIN
时加载字典。 BEGIN
时间与正在加载的文件有关。当你的 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;
}
您也可以从位于同一目录的 Dictionary.txt
加载。诀窍是您必须提供文件的绝对路径。您可以从 __FILE__
获取它,这是当前文件的路径(即 Dictionary.pm
)。
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);
你应该使用哪个? DATA
更容易分发。对于非编码人员来说,单独的并行文件更容易处理。
比在加载库时加载整个词典更好,等待在需要时加载它更有礼貌。
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};
}
每个对象现在都包含对共享字典的引用(消除了对全局的需要),它仅在创建对象时加载。
我建议使用 DATA
和 INIT
instead of BEGIN
以确保数据在 运行 时间之前初始化。它还使它更加自我记录
或者使用UNITCHECK
块可能更合适,它会尽早执行,在库文件编译后立即执行,因此可以认为是编译的扩展
package Dictionary;
use strict;
use warnings;
my %dictionary;
UNITCHECK {
while ( <DATA> ) {
chomp;
my ($k, $v) = split /,/;
$dictionary{$k} = $v;
}
}
将运行时所需的数据文件与 Perl 模块捆绑在一起的 "proper" 方法是什么,以便模块可以在使用前读取其内容?
一个简单的例子就是这个字典模块,它需要在启动时读取(单词,定义)对列表。
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 块:
BEGIN { open(FP, '<', 'Dictionary.txt') or die "Can't open: $!\n"; while (<FP>) { chomp; my ($word, $def) = split(/,/); $Dictionary{$word} = $def; } close(FP); }
没有骰子:Perl 正在 cwd 中查找 Dictionary.txt,这是主脚本 ("Main.pl") 的路径,而不是模块的路径,所以这给出了文件未找到。
使用数据:
BEGIN { while (<DATA>) { chomp; my ($word, $def) = split(/,/); $Dictionary{$word} = $def; } close(DATA); }
并在模块结束时
__DATA__ aardvark,an animal which is definitely not an anteater abacus,an oldschool calculator ...
这也失败了,因为 BEGIN 在编译时执行,在 DATA 可用之前。
硬编码模块中的数据
our %Dictionary = ( aardvark => 'an animal which is definitely not an anteater', abacus => 'an oldschool calculator' ... );
有效,但绝对不可维护。
这里有类似的问题:How should I distribute data files with Perl modules?但是那个问题涉及 CPAN 安装的模块,而不是我正在尝试做的与当前脚本相关的模块。
无需在 BEGIN
时加载字典。 BEGIN
时间与正在加载的文件有关。当你的 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;
}
您也可以从位于同一目录的 Dictionary.txt
加载。诀窍是您必须提供文件的绝对路径。您可以从 __FILE__
获取它,这是当前文件的路径(即 Dictionary.pm
)。
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);
你应该使用哪个? DATA
更容易分发。对于非编码人员来说,单独的并行文件更容易处理。
比在加载库时加载整个词典更好,等待在需要时加载它更有礼貌。
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};
}
每个对象现在都包含对共享字典的引用(消除了对全局的需要),它仅在创建对象时加载。
我建议使用 DATA
和 INIT
instead of BEGIN
以确保数据在 运行 时间之前初始化。它还使它更加自我记录
或者使用UNITCHECK
块可能更合适,它会尽早执行,在库文件编译后立即执行,因此可以认为是编译的扩展
package Dictionary;
use strict;
use warnings;
my %dictionary;
UNITCHECK {
while ( <DATA> ) {
chomp;
my ($k, $v) = split /,/;
$dictionary{$k} = $v;
}
}