Thread Problem mit FileHandle
(24 answers)
Opened by rosti at 2011-04-05 22:27
Was mir an dem Modul nicht so recht gefällt ist, dass es nicht mit mehren Dateien umgehen kann und das mehrfache tie Aufrufe entweder eine Fehlermeldung werfen (bless(undef,$class)), oder unabhängige Objekte erzeugen, die aber auf das selbe Handle schreiben. Das kann zu einem ziemlichen durcheinander führen.
Zudem ist "-auto" nicht sehr verständlich. "-increment" dagegen beschreibt recht genau was passiert. Weiterhin würde es mich stören, wenn nach dem tie neue Schlüssel angelegt werden können. Ich hätte auch einen anderen Paketnamen gewählt. Also hier mein Vorschlag: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 package PersistentCounter; use strict; use warnings; use IO::File; use File::Spec; use Carp; use Fcntl ':flock'; use Tie::Hash; use base 'Tie::ExtraHash'; use Storable qw(fd_retrieve store_fd); # VARs intern our %files; # Constructor sub TIEHASH { my $class = shift; my $ref = shift or return; croak ('No ref HASH in Arg') if ref $ref ne 'HASH'; croak('No file is given, use {-file => $file} in Args') if not exists $ref->{-file}; # autoincrement my $inc=$ref->{-increment}; $inc=[] if(!$inc || ref($inc) ne 'ARRAY'); # force initialize keys my $keys=$ref->{-keys}; $keys=[] if(!$keys || ref($keys) ne 'ARRAY'); my $self=_initialize($class,$ref->{-file}) or return undef; # IO-Error croak('No keys given, use {-keys => [...]} or {-increment => [...]}') if(!%{$self->[0]} && !(@$keys || @$inc)); for(@$keys) { $self->[0]->{$_}=0 unless(defined($self->[0]->{$_})); } # apply autoincrement for custom keys like 'foo', 'bar' $self->[0]->{$_}++ for(@$inc); return $self; } # Overload method, make sure that value is numeric and the key exisis sub STORE { my $self = shift; my $key = shift; my $value = shift; if(exists($self->[0]->{$key})) { if($value =~ /^\d+$/) { $self->[0]->{$key} = $value; } else { carp "Value is not numeric"; } } else { carp "Key not predefined"; } } sub FETCH { my $self = shift; my $key = shift; return $self->[0]->{$key} if(exists($self->[0]->{$key})); carp "Key not predefined"; return undef; } sub DESTROY { my $self = shift; _serialize($self); } ######################################################################## # hash from $file sub _initialize { my $class=shift; my $file = shift; $file=File::Spec->rel2abs($file); # return same object for one file; return $files{$file} if($files{$file}); my $self=[{},{ fh=>undef, file=>undef }]; my $fh=__file_open($file) or return undef; $self->[1]->{fh}=$fh; $self->[1]->{file}=$file; my $ref = {}; eval { $ref = fd_retrieve($fh) }; # caught exception: file is void $ref={} if($@); $self->[0]=$ref; bless($self,$class); $files{$file}=$self; return $self; } # hash to file sub _serialize { my $self = shift; # get all important values my $file=$self->[1]->{file}; my $fh=$self->[1]->{fh}; my $data=$self->[0]; # clean up object delete($self->[1]->{fh}); delete($self->[1]->{file}); $self->[0]=undef; $self->[1]=undef; @$self=(); unless($fh) { $fh=__file_open($file) or return; } $fh->seek(0,0); truncate($fh,0); store_fd($data, $fh); $fh->close(); delete($files{$file}); } sub __file_open { my $file=shift; my $fh=IO::File->new($file, O_CREAT|O_BINARY|O_RDWR) or return undef; flock($fh,LOCK_EX) or carp "Your system does not support flock()!"; $fh->binmode(':raw'); return $fh; } 1; Damit kann man ein wenig mehr anstellen: Code (perl): (dl
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #!/usr/bin/perl use strict; use warnings; use PersistentCounter; my $file1 = 'storecounter1.bin'; tie my %h1, 'PersistentCounter', {-file => $file1, -increment => ['foo','bar']} or die $!; my $file2 = 'storecounter2.bin'; tie my %h2, 'PersistentCounter', {-file => $file2, -increment => ['bam','bur']} or die $!; print "H1\n"; foreach my $k (sort keys %h1) { print "$k => $h1{$k}\n"; } print "H2\n"; foreach my $k (sort keys %h2) { print "$k => $h2{$k}\n"; } tie my %h3, 'PersistentCounter', {-file => $file1} or die $!; $h1{bar}++; $h3{bar}++; print "H3\n"; foreach my $k (sort keys %h3) { print "$k => $h3{$k}\n"; } |