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