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

标签 perl perl-module directory-structure data-files

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

一个简单的例子是这个 Dictionary 模块,它需要在启动时读取 (word,definition) 对的列表。

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 block :
    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”)的路径,而不是模块的路径,所以这给出了 File Not Found。
  • 使用数据:
    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 在编译时执行,在 之前数据 可用。
  • 硬编码模块中的数据
    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.pluse 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};
    }
    

    现在,每个对象都包含对共享字典的引用(无需全局),该字典仅在创建对象时加载。

    关于perl - 如何在 Perl 模块中包含数据文件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33535453/

    相关文章:

    perl - 用虚拟数据填充文件的一部分

    regex - 去除字符串但允许变音

    perl - 如何在函数内使用模块的 "member"变量?

    perl - perl 中的异常处理

    java - 如何使用 Inline::Java 连接到外部 JVM?

    ruby - 如何将 rails 应用程序(服务器代码)和 ruby​​ gem(客户端代码)组合到一个通用包中?

    c - 在C代码中获取文件的目录

    php - 连续执行perl脚本

    perl - 使用 Term::Readline:Zoid 时出现 "ViCommand: no such keymap"错误

    php - 使用 PHP RecursiveTreeIterator 构建日志读取器