【问题标题】:Using Storable to store hash and use it in another script使用 Storable 存储哈希并在另一个脚本中使用它
【发布时间】:2016-12-16 12:02:38
【问题描述】:

我将哈希存储在这样的脚本中(部分代码省略):

use strict;
use warnings;

use utf8;

use Storable qw(nstore_fd);

open( my $fh, ">",  'hash.hash');
my $hash_ref = \%hash;
nstore_fd($hash_ref, $fh);
close $fh;

这会创建一个文件hash.hash。然后,在另一个文件中,我尝试“导入”散列并读取其要使用的值(例如,循环散列、读取值、检查存在......)。

我尝试了一些简单的方法,即读取哈希、取消引用并读取其键,然后将其打印出来。但是我收到错误Not a HASH reference at CreateSql.pl line 12. 这是一个标量。但我不明白为什么。模块的The documentation 声明返回一个引用。

要检索存储到磁盘的数据,请使用带有文件名的retrieve。这 存储在该文件中的对象会为您重新创建到内存中,并且 返回对根对象的引用。

那么我做错了什么,如何访问存储的哈希?

use strict;
use warnings;

use utf8;

use Data::Dumper;
use Storable qw(retrieve);

my ($hash_path) = @ARGV;

my $hash_ref = retrieve($hash_path);

my @keys = keys % { $hash_ref }; # throws error
print Dumper(\@keys);

【问题讨论】:

  • 我也敦促 - 不要使用 Storable 来存储东西。有些开放格式通常更好,因为它们是可移植的,例如 JSON 或 YAML。 (也许是 XML,但前提是您确实需要 XML 的功能,这对于 大多数 应用程序来说太过分了)
  • @Sobrique 存储散列的唯一目标是在另一个脚本中使用。即使在这种情况下,您认为在第一个脚本中编码为 JSON,然后在第二个脚本中以新的哈希读取 JSON 是否更好?我不太了解存储和效率,但是从速度上看,这似乎不是很有效。数据永远不会在这两个脚本之外使用,所以我认为不需要通用数据类型。考虑到脚本的效率,您怎么看?
  • 除非您的数据量很大,否则它会产生微小的差异。如果您的数据很大,那么以这种方式转储数据结构无论如何都不是一个好计划。对于互操作性、支持和诊断,IMO 的人类可读选项只是出于样式原因而更好。
  • 我同意@Sobrique ...虽然Storable 很棒,但我过去在不同版本的发行版中遇到过问题。 JSON 同样简单易用,而且它的格式是一个非常一致的标准。它也是跨语言的。此外,“数据永远不会在这两个脚本之外使用”......我总是假设相反,只是为了安全。
  • Re "但在速度方面这似乎不是很有效",我不明白为什么它不会有效。 JSON 解析起来非常简单。

标签: perl hash reference


【解决方案1】:

你真的必须展示给你所描述的问题的代码,否则很难帮助你。您问题中的代码无法编译。如果您想在发布程序之前对其进行更改,再次测试以确保它至少可以编译,并显示您报告的问题

主要问题是您将二进制数据写入以文本形式打开的文件。如果您将open( my $fh, ">", 'hash.hash') 更改为open( my $fh, ">:raw", 'hash.hash'),那么一切正常

您自己的代码变体可以正确存储和检索一些示例数据

use strict;
use warnings 'all';

use Storable qw/ nstore_fd retrieve /;

use constant STORAGE => 'hash.hash';

my %hash = ( a => 'b', c => 'd' );

{
    open my $fh, '>:raw',  STORAGE or die $!;
    nstore_fd \%hash, $fh;
}

my $hash_ref = retrieve STORAGE;

use Data::Dump;

dd $hash_ref;

my @keys = keys % { $hash_ref }; # throws error
dd \@keys;

输出

{ a => "b", c => "d" }
["a", "c"]

但是,您做出了一些奇怪的选择。无需使用nstore 函数以“网络顺序”存储数据,如果您让模块自己打开文件,您可以完全避免这个问题

这是一个仅使用storeretrieve 的变体。输出与上面的代码相同

use strict;
use warnings 'all';

use Storable qw/ store retrieve /;

use constant STORAGE => 'hash.hash';

my %hash = ( a => 'b', c => 'd' );

store \%hash, STORAGE;

my $hash_ref = retrieve STORAGE;

use Data::Dump;

dd $hash_ref;

my @keys = keys % { $hash_ref }; # throws error
dd \@keys;

【讨论】:

  • 嗯,不。第一部分没有编译,因为我遗漏了一堆 - 正如我明确指出的那样。在我看来(正确地)错误出现在我显示的代码中,这与我可以提供的任何其他代码无关。使用:raw 解决了该问题。谢谢。 (不知道为什么这个问题应该投反对票。)网络商店确实没有必要。但我确实需要store_fd,因为我正在脚本的多个位置写入(已经打开的)文件。至少我是这么理解这个选项的。
  • @BramVanroy:投票结束问题的原因之一是“寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包含所需的行为、特定问题或错误以及在问题本身中重现它所需的最短代码。” (强调原文。)因此,您可以进行近距离投票,而不仅仅是反对票。您不知道问题出在哪里,您应该发布一个显示相同问题的工作示例。另请阅读How do I ask a good question?
  • @BramVanroy:“我确实需要 store_fd,因为我在脚本的多个位置写入(已经打开的)文件” 在这种情况下,您需要使用 @987654332 @ 反而。 retrieve 将重复获取存储的第一个数据结构。
  • 如果这两个脚本通过文件进行通信,那么文件可能不是正确的选择。改用套接字怎么样?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-04-27
  • 2012-02-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-03
  • 2015-10-25
相关资源
最近更新 更多