Storableのstore_fdとfd_retrieveを使用すると、データ構造をプログラム自体のDATAファイルハンドルに格納できるかどうか知りたいと思いました。これはベストプラクティスではないことに気づきました。うまくいくかどうか知りたいだけです。すぐに試してみてもうまくいかないようです。
4 に答える
なぜあなたがそれをしたいのか分かりませんが、あなたはそれを偽造することができます。ただし、それは避けてください。
ちょっとした笑いのために、ファイルハンドルを開いて、から行を読み取り、$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
DATA
スクリプトとともに保存されたデータを読み取るためのハンドルです。ConwayのInline::Filesは、書き込み可能な仮想ファイルについて話す、私が知っている唯一のモジュールです。また、スクリプトファイルは通常ASCIIであるため、Storableの出力でMSDOSのバイナリ26バイトまたはUNIXのバイナリ4を取得した場合、どうなるかわかりません。
ただし、データを入力して保存し、スクリプトから読み取るだけの場合は、バイナリの問題が発生します。
したがって、永続性のためにYAMLまたはJSONを使用することをお勧めします。YAMLがDATAからデータを取得するときに祝福を処理することを知っています。
通常の状態では不可能です:
$ cat write-data
#! /usr/bin/perl
use warnings;
print DATA "bar!\n";
$ ./write-data
名前"main:: DATA"は1回だけ使用されます:./write-data行6でタイプミスの可能性があります。
./write-data行6の未開封のファイルハンドルDATAのprint()。
しかし、あなたは異常な条件を作り出すことができます:
#! /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;
unlink
Windowsでは、デフォルトのファイル共有セマンティクスのために警告が表示されます。それがプラットフォームの場合は、その時点でクリーンアップするか、 Win32::SharedFileOpenEND
を使用できます。
私は自分自身の解決策を思いついた...それや他の人を特にお勧めするわけではない。私の場合、それは多次元ハッシュ構造の参照値を持つ単体テストスクリプトです。これが何をするのか、そしてその理由の技術的な詳細には立ち入りませんが、最終的には、コードの小さな修正または変更により、多くの値を更新する必要があります(変更が有効であることを検証した後)。
したがって、を使用してハッシュを__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__
は$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);
1つのミスですべてのコードが破壊される可能性があるため、開発中はファイルのバックアップを必ず保持してください。
Storable
また、同じことが;でも機能することに注意してください。ストレージはより効率的かつ高速になります。唯一の注意点は、バイナリであるということです。つまり、ファイルの差分がソース管理に表示されない可能性があり、Dumperの出力ほど編集が簡単ではありません。