【问题标题】:Tie Reading and Writing Perl Config Files连接读写 Perl 配置文件
【发布时间】:2013-06-06 14:04:24
【问题描述】:

我正在使用我在以下网站上找到的 PerlMonk 示例: Reading and Writing Perl Config Files

配置.pl:

%CFG = (
    'servers' => {
        'SRV1' => {
            'IP'     => 99.32.4.0,
            'user'   => 'aname',
            'pswd'   => 'p4ssw0rd',
            'status' => 'unavailable'
        },
        'SRV2' => {
            'IP'     => 129.99.10.5
            'user'   => 'guest',
            'pswd'   => 'guest'
            'status' => 'unavailable'
        }
    },
    'timeout' => 60,
    'log' => {
        'file'  => '/var/log/my_log.log',
        'level' => 'warn',
    },
    'temp' => 'remove me'
);

它工作得很好,但唯一的问题是在读取和写入类似 HASH 的配置时“无序”。 有没有办法让它保持绑定?

这很重要,因为配置文件也会手动编辑,所以我希望键和值的顺序相同。

【问题讨论】:

  • 将数据存储为 Perl 代码是一个坏主意。最好是JSON,这也解决了你保持数据有序的问题。

标签: perl file configuration tie


【解决方案1】:

您可以在使用之前tie 配置变量,因此以后的哈希键将保持与以前相同的顺序,

use strict;
use warnings;

use Tie::IxHash;
tie my %CFG, 'Tie::IxHash';

%CFG = (
    'servers' => {
        'SRV1' => {
            'IP'     => '99.32.4.0',
            'user'   => 'aname',
            'pswd'   => 'p4ssw0rd',
            'status' => 'unavailable'
        },
        'SRV2' => {
            'IP'     => '129.99.10.5',
            'user'   => 'guest',
            'pswd'   => 'guest',
            'status' => 'unavailable'
        }
    },
    'timeout' => 60,
    'log' => {
        'file'  => '/var/log/my_log.log',
        'level' => 'warn',
    },
    'temp' => 'remove me'
);

use Data::Dumper;
print Dumper \%CFG;

【讨论】:

  • 您还必须绑定所有内部哈希。您还可以将$Data::Dumper::Sortkeys 设置为真值或对排序子例程的引用。
  • @mob 似乎有 Tie::Autotie 但哈希值应该在当时填充一个键/值。
  • mpapec & @mob,谢谢,我会试一试...即使是你,把每个内部 HASH 联系起来似乎都是这个想法的杀手。
【解决方案2】:

如果您使用JSON,那么您的优势是您的软件可以免受恶意攻击(或可能是意外损坏)。 JSON 的语法也比 Perl 数据结构更简单,更容易从语法错误中恢复。

设置canonical 选项将创建具有排序顺序的键的数据,因此每次都为相同的 Perl 数据生成相同的输出。如果您需要按字母顺序以外的特定顺序的数据,那么您可以使用@mpapec 在他的回答中描述的Tie::IxHash 模块。

或者,您可以使用纯 Perl 版本的模块中的 sort_by 方法,该方法允许您传递排序规则子例程。这可以让您指定键的顺序,并且可以像使用将所有可能的键值与数字排序顺序相关联的哈希一样简单。

此程序使用sort_by 方法以与原始哈希中键出现的顺序相同的顺序重构 JSON。这不太可能是您想要的顺序,但机制就在那里。它通过查找哈希表中的每个键来确定它们应该如何排序。默认情况下,未出现在哈希中的任何键(如 SVR1SVR2 此处)按字母顺序排序。

use strict;
use warnings;

use JSON::PP ();

my %CFG = (
  'servers' => {
    'SRV1' => {
      'IP'     => '99.32.4.0',
      'user'   => 'aname',
      'pswd'   => 'p4ssw0rd',
      'status' => 'unavailable'
    },
    'SRV2' => {
      'IP'     => '129.99.10.5',
      'user'   => 'guest',
      'pswd'   => 'guest',
      'status' => 'unavailable'
    }
  },
  'timeout' => 60,
  'log'     => {
    'file'  => '/var/log/my_log.log',
    'level' => 'warn',
  },
  'temp' => 'remove me'
);

my %sort_order;
my $n = 0;
$sort_order{$_} = ++$n for qw/ servers timeout log temp /;
$sort_order{$_} = ++$n for qw/ IP user pswd status /;
$sort_order{$_} = ++$n for qw/ file level /;

my $json = JSON::PP->new->pretty->sort_by(\&json_sort);
print $json->encode(\%CFG);

sub json_sort {
  my ($aa, $bb) = map $sort_order{$_}, $JSON::PP::a, $JSON::PP::b;
  $aa and $bb and $aa <=> $bb or $JSON::PP::a cmp $JSON::PP::b;
}

产生这个输出

{
   "servers" : {
      "SRV1" : {
         "IP" : "99.32.4.0",
         "user" : "aname",
         "pswd" : "p4ssw0rd",
         "status" : "unavailable"
      },
      "SRV2" : {
         "IP" : "129.99.10.5",
         "user" : "guest",
         "pswd" : "guest",
         "status" : "unavailable"
      }
   },
   "timeout" : 60,
   "log" : {
      "file" : "/var/log/my_log.log",
      "level" : "warn"
   },
   "temp" : "remove me"
}

可以简单地保存到文件中并以类似方式恢复。

【讨论】:

  • 我同意 JSON 可能会更好,特别是因为我正在考虑将来将该项目从 Perl 迁移到 Python。关于IP地址的问题,我同意,我已经把它改成字符串了,我使用的例子来自原始示例帖子。
  • 我已经测试了这两个选项...我的配置文件有太多的内部哈希,我懒得把它们全部捆绑起来。因此,使用带有规范标记的 JSON 将合乎逻辑且具有成本效益。谢谢。
  • @tal.tzf:很高兴你找到了解决方案。
  • @tal.tzf:JSON 的纯 Perl 实现提供了一个 sort_by 方法,允许您传递一个排序子例程。这将让您规定键的顺序,并且可以像使用将所有可能的键值与数字排序顺序相关联的哈希一样简单。
  • @tal.tzf:我已经修改了我的答案,以展示如何通过使用 sort_by 方法传递自定义排序子例程来生成您喜欢的任何键顺序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-19
  • 2012-06-22
  • 2014-02-14
  • 2011-07-02
  • 2013-04-15
  • 1970-01-01
相关资源
最近更新 更多