Storageable 可以存储到 DATA 文件句柄吗?

发布于 2024-08-20 14:27:40 字数 199 浏览 10 评论 0 原文

我很好奇使用 Storable 的 store_fd 和 fd_retrieve 是否允许我存储将数据结构放入程序自己的 DATA 文件句柄中。我意识到这不是最佳实践,我只是好奇它是否有效,我的快速尝试似乎不起作用。

I was curious if using Storable's store_fd and fd_retrieve would allow me to store a data structure into a program's own DATA filehandle. I realize this isn't Best Practice, I'm just curious if it'd work, my quick attempts to try it don't seem to work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

一世旳自豪 2024-08-27 14:27:40

我不确定你为什么要这样做,但你可以假装它。但你应该尽量避免这种情况。

只是为了咯咯笑,您可以打开一个文件句柄,从 $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

I'm not sure why you'd want to do that, but you can fake it. You should try to avoid that though.

Just for giggles, you could open a filehandle, read lines from $0 and print them until you get to __DATA__, then add your new __DATA__ section. The trick is then to rename your new file to become $0, perhaps by an exec if your system locks the file while the program is running:

#!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
沫离伤花 2024-08-27 14:27:40

DATA 是一个句柄,用于读取与脚本一起存储的数据。 Conway 的 Inline::Files 是我临时知道的唯一谈论可写虚拟文件。由于脚本文件通常是 ASCII,我不知道如果在 Storable 的输出中得到 MSDOS 上的二进制 26 字节或 UNIX 上的二进制 4 会发生什么。

但是,如果您谈论的是通过在其中键入来存储数据,只是为了从脚本中读取数据,那么二进制问题仍然存在面对你。

因此,最好使用 YAMLJSON 用于持久性。我知道 YAML 在从 DATA 检索数据时会处理祝福。

DATA is a handle to read data stored with the script. Conway's Inline::Files is the only module I know offhand that talks of writable virtual files. And since script files are usually ASCII I don't know what would happen if you got a binary 26 byte on MSDOS or a binary 4 on UNIX in the output of Storable.

However, if you are talking about you storing data by typing it in there, only to read it from a script, then the binary problem still confronts you.

So, it's better to go with YAML or JSON for persistence. I know that YAML will handle the blessing when retrieving the data from DATA.

無處可尋 2024-08-27 14:27:40

在正常情况下这是不可能的:

$ 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

It's not possible in ordinary conditions:

$ 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.

But you can create extraordinary conditions:

#! /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;

On Windows, you'll get a warning on the unlink because of its default file-sharing semantics. If that's your platform, you can clean up at END time or use Win32::SharedFileOpen.

羁〃客ぐ 2024-08-27 14:27:40

我想出了自己的解决方案......并不是我特别推荐它或任何其他解决方案;就我而言,它是一个单元测试脚本,具有多维哈希结构中的参考值。我不会详细介绍这个东西的作用和原因,但最终结果是代码中的一个小修复或更改可能会导致许多值需要更新(在验证更改有效之后)。

因此,我使用 Data::Dumper 将哈希移至 __DATA__ 部分。将其写入文件句柄的代码如下所示:

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__ 部分,我在 $FILEPOS 打开 __FILE__,截断它并写入。我简化了此示例的错误处理。

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);

请务必在开发时保留文件备份,因为一个错误可能会毁掉您的所有代码!

另请注意,这同样适用于 Storable;存储将更加高效、更快。唯一需要注意的是它是二进制的,这意味着文件差异可能不会显示在源代码管理中,并且它不像 Dumper 的输出那样容易编辑。

I came up with my own solution... not that I specifically recommend it or any others; in my case it's a unit test script with reference values in a multi-dimensional hash structure. I won't go into the technical details of what this things does and why, but the end result is that a small fix or change in the code can result in many values requiring an update (after validating the change is valid).

Therefore I moved the hash into the __DATA__ section using Data::Dumper. The code to write that to a file handle looks like:

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);

At the beginning of the script I load the hash from DATA after storing references to the initial handle's position and mtime (mtime is used to ensure the file hasn't been modified during the script's execution).

use vars qw(%HASH $FILEPOS $MTIME);

{
    $FILEPOS = tell(DATA);
    $MTIME = (stat(DATA))[9];
    local $/;
    my $data = <DATA>;
    %HASH = %{eval $data};
}

Finally, to update the __DATA__ section I open __FILE__ at $FILEPOS, truncate it and write to it. I simplified error handling for this example.

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);

Be sure to keep backups of your files as you develop as a single mistake could destroy all your code!

Also note that the same would work with Storable; storage would be more efficient and faster. The only caveat is that it's binary, which means file diff will likely not show up in source control, and it's not as easy to edit as Dumper's output.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文