我很好奇如果使用Storable的store_fd和fd_retrieve将允许我将数据结构存储到程序自己的DATA文件句柄中。我意识到这不是最佳实践,我只是好奇它是否有效,我尝试它的快速尝试似乎不起作用。
答案 0 :(得分:2)
我不确定你为什么要这样做,但你可以伪造它。你应该尽量避免这种情况。
只是为了咯咯笑,你可以打开一个文件句柄,从$0
读取行并打印它们直到你到达__DATA__
,然后添加新的__DATA__
部分。然后,如果系统在程序运行时锁定文件,则可以通过$0
将新文件重命名为exec
:
#!perl
my $mode = (stat($0))[2] & 07777;
open my($fh), '<', $0 or die "I can't open me! $!\n";
open my($new), '>', "$0.new" or die "I can't open you! $!\n";
eval { chmod( $mode, $new ) } or warn "Couldn't set permissions: $@\n";
while( <$fh> )
{
last if /^__DATA__$/;
print { $new } $_;
}
print "I am $$\n";
print { $new } "__DATA__\n", join '|', $$, time, (stat($0))[1];
rename( "$0.new", $0 )
__DATA__
64574|1265415126|8843292
答案 1 :(得分:1)
DATA
是读取与脚本一起存储的数据的句柄。 Conway的Inline::Files是我所知道的唯一可以讨论可写虚拟文件的模块。由于脚本文件通常是ASCII,我不知道如果在MSDOS上有二进制26字节,或者在Storable的输出中有UNIX上的二进制4,会发生什么。
但是,如果你在谈论你通过输入来存储数据,只有从脚本中读取它,那么二元问题仍然面临着你。
答案 2 :(得分:1)
在普通条件下这是不可能的:
$ cat write-data
#! /usr/bin/perl
use warnings;
print DATA "bar!\n";
$ ./write-data
Name "main::DATA" used only once: possible typo at ./write-data line 6.
print() on unopened filehandle DATA at ./write-data line 6.
但是你可以创造非凡的条件:
#! /usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use File::Temp qw/ tempfile /;
use Storable qw/ store_fd fd_retrieve /;
sub store_in_DATA {
my($data) = @_;
my($fh,$path) = tempfile;
unlink $path or warn "$0: unlink: $!";
*DATA = $fh;
store_fd $data, \*DATA or warn "$0: print: $!";
seek DATA, 0, 0 or warn "$0: seek: $!";
}
store_in_DATA { foo => "There is no spoon.\n" };
undef $/;
my $ref = fd_retrieve \*DATA;
print Dumper $ref;
在Windows上,由于其默认的文件共享语义,您将在unlink
上收到警告。如果这是您的平台,您可以在END
时间进行清理或使用Win32::SharedFileOpen。
答案 3 :(得分:0)
我提出了自己的解决方案......不是我特别推荐它或其他任何解决方案;在我的例子中,它是一个单元测试脚本,在多维哈希结构中具有引用值。我不会详细介绍这些内容的作用和原因,但最终结果是代码中的小修复或更改会导致许多值需要更新(在验证更改后有效)。
因此,我使用__DATA__
将哈希移动到Data::Dumper
部分。将其写入文件句柄的代码如下所示:
use Data::Dumper;
$Data::Dumper::Terse = 1; # to Eval whole thing as a hash
$Data::Dumper::Indent = 1; # Looks better, just a preference
$Data::Dumper::Sortkeys = 1; # To keep changes minimal in source control
print $fh Dumper(\%HASH);
在脚本开始时,我在存储对初始句柄位置和mtime的引用后加载来自DATA
的哈希值(mtime用于确保在脚本执行期间文件未被修改)。
use vars qw(%HASH $FILEPOS $MTIME);
{
$FILEPOS = tell(DATA);
$MTIME = (stat(DATA))[9];
local $/;
my $data = <DATA>;
%HASH = %{eval $data};
}
最后,要更新我在__DATA__
打开__FILE__
的{{1}}部分,请将其截断并写入。我简化了这个例子的错误处理。
$FILEPOS
请确保在开发过程中保留文件的备份,因为单个错误可能会破坏您的所有代码!
另请注意,同样适用于open(my $fh, '>>', __FILE__) or die $!;
seek($fh, $FILEPOS, 0) or die $!;
die "File changed" if ((stat($fh))[9] != $MTIME);
truncate($fh, $FILEPOS) or die $!;
# Assumes Dumper is already loaded and configured as in first code snippet
print $fh Dumper(\%HASH);
;存储将更有效,更快捷。唯一需要注意的是它是二进制文件,这意味着文件差异很可能不会出现在源代码控制中,并且编辑它并不像Dumper的输出那么容易。