Thread Problem mit FileHandle (24 answers)
Opened by rosti at 2011-04-05 22:27

topeg
 2011-04-07 16:30
#147452 #147452
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
2011-04-07T08:09:18 rosti
Ein paar Fragen dazu: Hast Du mit use File::Spec; da noch was vor, wenn ich das auskommentiere, ist es ohne Effekt.

Ich nutze es um relative Pfade in absolute zu wandeln. $file=File::Spec->rel2abs($file) damit stelle ich sicher, dass eine Datei nicht zweimal geöffnet wird.

2011-04-07T08:09:18 rosti
Und was ist der Unterschied zwischen Tie::ExtraHash und Tie::StdHash?

Tie::ExtraHash erlaubt es extra Werte, die nicht von außen lesbar sie unter zu bringen. Ich packe da das Filehandle rein.

2011-04-07T08:09:18 rosti
Meine alte Perl-Version 5.6.1 kennt nur StdHash

Schneide es aus dem Cpan modul aus und packe es als eigenes Modul dazu. Oder reimplementiere es selber

2011-04-07T08:09:18 rosti
Also: brauchen wir ein require v??? für Deine Änderungen?


2011-04-07T08:09:18 rosti
Wir brauchen entweder noch ein paar Methoden für $ob = tied(%hash); oder überschreiben DELETE() und STORE(), damit Keys zur Laufzeit gelöscht oder hinzugefügt werden können.

Edit2: Ok, der Sinn predefined Keys ist klar. STORE() funktioniert nur mit predefined Keys und ist gut so. Ich überschreibe mal DELETE() so, dass es mit predefined keys (und nur mit diesen) tut.

Ich fand es halt wichtig, dass man so Tippfehlern vorbeugen kann.

2011-04-07T08:09:18 rosti
use Yes;
Ich schreibe die POD und teste das Modul bis zur Produktionsreife.
=item Authors
Du und ich ;)

Enstchuldige wenn ich dir mühen mache, aber ich ahbe einen schlimmen fehler in dem Code gefunden den ich gestern Nacht in einer Stunde zusammen geklatscht habe.
Wenn ich Das Objekt selber in einer Paketvariable speichere, dann wird es erst zerstört, wenn das Script sich beendet. Das ist ja so nicht gewünscht. Darum eine neue Variante.

In dem Zug hab ich auch gleich nur von Tie::Hash geerbt und CWD::abs_path genutzt. Das sollte auch mit einem älterem Perl funktionieren.

more (42.2kb):
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
package PersistentCounter;

use strict;
use warnings;
use IO::File;
use Cwd 'abs_path';
use Carp;
use Fcntl ':flock';
use base 'Tie::Hash';
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');

  # get a new object
  my $self=$class->_initialize($ref->{-file}) or return undef; # IO-Error

  # get object data
  my $data=$self->_get_data();

  croak('No keys given, use {-keys => [...]} or {-increment => [...]}') if(!%$data && !(@$keys || @$inc));

  for(@$keys)
  { $data->{$_}=0 unless(defined($data->{$_})); }

  # apply autoincrement for custom keys like 'foo', 'bar'
  $data->{$_}++ 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;
  my $data=$self->_get_data();
  if(exists($data->{$key}))
  {
    if($value =~ /^\d+$/)
    { $data->{$key} = $value; }
    else
    { carp "Value is not numeric"; }
  }
  else
  { carp "Key not predefined"; }
}

sub FETCH
{
  my $self = shift;
  my $key = shift;
  my $data=$self->_get_data();
  return $data->{$key} if(exists($data->{$key}));

  carp "Key not predefined";
  return undef;
}

sub EXISTS
{
  my $self = shift;
  my $key = shift;
  my $data=$self->_get_data();
  return exists($data->{$key});
}

sub DELETE
{
  my $self = shift;
  my $key = shift;
  my $data=$self->_get_data();
  return delete($data->{$key}) if(exists($data->{$key}));

  carp "Key not predefined";
  return undef
}

sub FIRSTKEY
{
  my $self = shift;
  my $data=$self->_get_data();
  $self->{keys}=[keys(%$data)];
  return shift(@{$self->{keys}});
}

sub NEXTKEY
{
  my $self = shift;
  return shift(@{$self->{keys}});
}

sub CLEAR
{
  my $self = shift;
  my $data=$self->_get_data();
  %$data=();
}

sub SCALAR
{
  my $self=shift;
  return $self->{file};
}

sub UNTIE
{
  my $self = shift;
  $self->_serialize();
}

sub DESTROY
{
  my $self = shift;
  $self->_serialize();
}

########################################################################

# get the Loaded Hash
sub _get_data
{
  my $self=shift;
  return $files{$self->{file}}->{data};
}

# hash from $file
sub _initialize
{
  my $class=shift;
  $class=ref($class) if(ref($class));
  my $file = shift;
  # absolut path for identification

  $file=abs_path($file);

  # return same object for one file;
  unless($files{$file})
  {
    my $fh=__file_open($file) or return undef;
    $files{$file}->{fh}=$fh;
    $files{$file}->{file}=$file;

    my $ref = {};
    eval { $ref = fd_retrieve($fh) };
    # caught exception: file is void
    $ref={} if($@);

    $files{$file}->{data}=$ref;
  }

  my $self={file=>$file, keys=>[]};
  bless($self,$class);

  # object count
  # only save and close file if all objects are distroyd
  $files{$file}->{objcount}++;

  return $self;
}

# hash to file
sub _serialize
{
  my $self = shift;
  my $file=$self->{file};

  # should be ok every time
  if(exists($files{$file}))
  {
    $files{$file}->{objcount}--;

    # make sure no more Objects using the file
    if($files{$file}->{objcount}==0)
    {
      my $data=$files{$file}->{data};
      my $fh=$files{$file}->{fh};
      delete($files{$file}->{fh});

      unless($fh)
      { $fh=__file_open($file) or return; }

      $fh->seek(0,0);
      truncate($fh,0);
      store_fd($data, $fh);
      $fh->close();

      delete($files{$file});
    }
  }
}

# open and lock 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;

View full thread Problem mit FileHandle