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

topeg
 2011-04-06 02:03
#147405 #147405
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
Wofür brauchst du ein Modul, das mit zählt wie häufig das Modul bezügliche eines Schlüssel zusammen ge"tie"d wurde?
Wenn es dir um das Zählen geht, würde da nicht eine einfache Funktion ausreichen?
Etwa so was:
more (8.4kb):
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
package NumberCount;

use strict;
use warnings;
use Carp;
use Storable;

use base 'Exporter';
our @EXPORT=qw(count_up count_last);

# VARs intern
my %vars = ();

sub count_up
{
  my $ref=&__get_count_ref;
  $$ref++;
  return $$ref
}

sub count_last
{
  my $ref=&__get_count_ref;
  return $$ref;
}

########################################################################
sub END
{
  for my $file (keys(%vars))
  { store($vars{$file}, $file); }
}

sub __get_count_ref
{
  my $file=shift //croak "No file";
  my $key=shift // croak "No key!";
  $file=File::Spec->rel2abs($file);
  unless(exists($vars{$file}))
  {
    if(-f $file)
    { $vars{$file}=retrieve($file) // {}; }
    else
    { $vars{$file}={}; }
  }

  return \$vars{$file}->{$key};
}

1;


Außerdem würde ich CPAN:Storable zum Serialisieren nutzen, das ist schneller als while zusammen mit pack/unpack

Oder willst du zahlen zu einem Schlüssel persistent halten?

Ich hatte mal ein Modul geschrieben das so was macht:
more (22.8kb):
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
package Tie::Scalar::StorageKeyList;

use strict;
use warnings;
use Carp;
use File::Spec;
use Storable;
use base 'Tie::Scalar';

my %objects;

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

sub TIESCALAR
{
  my $class=shift;
  pop(@_) if(@_%2);
  my %conf=@_;

  my $file =$conf{file}  // croak qq(No file, use "file" in options!);
  my $key  =$conf{key}   // croak qq(No key, use "key" in options!);
  my $value=$conf{value};
  my $pos=defined($conf{position})?int(abs($conf{position})):undef;

  $file=File::Spec->rel2abs($file);
  $objects{$file}{keys}=__load($file) unless(exists($objects{$file}));
  $objects{$file}{counter}++;

  if(defined($pos))
  {
    if($pos >= $objects{$file}{keycount}{$key})
    { $objects{$file}{keycount}{$key}=$pos+1; }
  }
  else
  {
    $objects{$file}{keycount}{$key}++;
    $pos=$objects{$file}{keycount}{$key}-1;
  }

  my $ref=\$objects{$file}{keys}{$key}[$pos];
  $$ref=$value unless(defined($$ref));

  my $self={file=>$file, key=>$key, val=>$ref };
  return bless($self,$class);
}

sub FETCH
{
  my $self=shift;
  return ${$self->{val}};
}

sub STORE
{
  my $self=shift;
  my $val=shift;
  ${$self->{val}}=$val;
}

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

  $objects{$file}{counter}--;

  __save($file,$objects{$file}{keys}) if($objects{$file}{counter}==0);
}

sub delete
{
  my $self=shift;


  my $p;
  my $arr=$objects{$self->{file}}{keys}{$self->{key}};
  for(0..$#$arr)
  {
    my $ref=\$arr->[$_];
    if($ref eq $self->{var})
    {
      $p=$_;
      last;
    }
  }

  if(defined($p))
  {
    $objects{$self->{file}}{keycount}{$self->{key}}--;
    return splice(@$arr,$p,1);
  }

  return undef;
}

########################################################################
########################################################################
sub __load
{
  my $file=shift;
  return retrieve($file) if(-f $file);
  return {};
}

sub __save
{
  my $file=shift;
  my $data=shift;
  return 0 unless $data;
  store($data, $file);
}

1;

Ich brauchte zu einem Schlüssel eine Reihe von Werten, die ich persistent gespeichert wissen wollte.

EDIT:
Mir fällt gerade auf, dass $fh als Paketvariable definiert ist. Es kann passieren, dass $fh auf die falsche Datei zeigt, und dass jede andere nicht geöffnete aber benutzte Datei nicht gespeichert wird.
Weiterhin ließt du immer den gesamten Inhalt aus der Datei und überschreibst damit bei jedem tie alle geänderten Werte. Das ist wohl genau dein Problem. Damit kann der Wert eines Schlüssels, bei existierenden Dateien und gespeicherten Schlüsseln, nur um 1 über den gespeicherten Wert steigen.
Wenn du eine Prüfung einfügst, in der du testest ob die Datei schon geladen wurde, sollte es Funktionieren.
Last edited: 2011-04-06 02:27:02 +0200 (CEST)

View full thread Problem mit FileHandle