hotti: FileHandle in Objekt mitführen

hi,

nach langer Zeit bin ich mal wieder am Überarbeiten meiner Module, mein Modul HashFile verwendet Serialize und Serialize::Hash (eigene Module). Letzteres erstellt ein Handle auf die Datei, das Handle wird im Namespace HashFile als globale Variable gehalten. Es besteht die Notwendigkeit, dass das FH über den gesamten Prozess leben muss.

Die Anwendung HashFile geht dann beispielsweise so:

tie my %hash, 'HashFile', '/tmp/hashfile', 'lock' or die $!;  

Ein tied(%hash) zeigt mir den Hash als Objekt, zur Klasse HashFile gehörig, soweit sogut. Was mir nicht gefällt, ist die globale Variable "FileHandle" (FH). Es bestünde nun die Möglichkeit, FH einfach in %hash einzufügen, damit werden jedoch einige Operationen verbaut, z.B. %hash = (); desweiteren ist der Key "FH" bei jeder anderen Operation immer zu berücksichtigen, das erscheint mir nicht sauber.

Welche Möglichkeiten gibt noch, auf die globale Variable "FH" zu verzichten?

Bitte mal um Hinweise,
Hotti

  1. Hallo,

    also bei PHP nimmst du getter und setter - Methoden und behandelst die Variablen sowieso fast immer private oder protected. Dann sind sie nur für die Funktionen innerhalb der Klasse verfügbar. "Global" brauchst du sie doch nur, wenn eine andere Klasse darauf zugreifen können soll. Bei einem FileHandle fragt man sich vermutlich, warum.

    Gruß

    jobo

    1. Hallo,

      also bei PHP nimmst du getter und setter - Methoden und behandelst die Variablen sowieso fast immer private oder protected. Dann sind sie nur für die Funktionen innerhalb der Klasse verfügbar. "Global" brauchst du sie doch nur, wenn eine andere Klasse darauf zugreifen können soll. Bei einem FileHandle fragt man sich vermutlich, warum.

      Hmm, so gesehen ist ja meine Variable {FileHandle} gar nicht global. Sie steht nur im Namespace der Klasse zur Verfügung. Naja, dann belasse ich das auch dabei ;-)

      Die Frage ist klar (und auch überschlafen): Das FileHandle wird nur innerhalb der Klasse gebraucht. Es besteht kein Grund, das anders zu machen, etwa einen Zugriff auf FH vom Script-Code aus und in die öffentliche Datenstruktur gehört ein FH gleichgarnicht.

      Viele Grüße,
      danke fürs Interesse,
      Hotti

      --
      Wenn der Kommentar nicht zum Code passt, kann auch der Code falsch sein.
  2. Moin Moin!

    Ein tied(%hash) zeigt mir den Hash als Objekt, zur Klasse HashFile gehörig, soweit sogut. Was mir nicht gefällt, ist die globale Variable "FileHandle" (FH). Es bestünde nun die Möglichkeit, FH einfach in %hash einzufügen, damit werden jedoch einige Operationen verbaut, z.B. %hash = (); desweiteren ist der Key "FH" bei jeder anderen Operation immer zu berücksichtigen, das erscheint mir nicht sauber.

    open my $handle,$mode,$name ist bekannt?


    IO::Handle
    und davon abgeleitete Klassen wie z.B. IO::File sind bekannt?

    Tie::StdHash und Tie::ExtraHash sind bekannt?

    Wo ist dann noch das Problem? ;-)

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
    1. hi,

      Wo ist dann noch das Problem? ;-)

      gelöst.

      Mein Tipp nur für Dich: sysopen() statt open();

      Hotti

    2. Moin,

      Tie::StdHash und Tie::ExtraHash sind bekannt?

      Ich muss nochmal nachfragen, ein tied(%hash) sieht z.B. so aus:

      bless({ 1 => "Eins", 2 => "Zwei" }, "HashFile")

      Würdest Du da ein Dateihandle reintun?

      Hotti

      1. Moin Moin!

        Moin,

        Tie::StdHash und Tie::ExtraHash sind bekannt?

        Ich muss nochmal nachfragen, ein tied(%hash) sieht z.B. so aus:

        bless({ 1 => "Eins", 2 => "Zwei" }, "HashFile")

        Fang mal RTFM mit Tie::ExtraHash an.

        Das Innenleben eines tied Hash und seine Außendarstellung müssen nicht zwangsläufig etwas miteinander zu tun haben.

        Du kannst z.B. aus TIEHASH() auch völlig schmerzfrei eine blessed Array Reference zurückgeben (oder beliebige andere blessed References, seien es Scalare, Hashes oder Globs; Code- und Regexp-Referenzen müßten auch funktionieren, fraglich nur, ob das sinnvoll ist). Perl will nur irgendein Objekt haben, auf dem es die diversen Methoden aufrufen kann. Wie die Methoden zu ihren Ergebnissen kommen, ist völlig egal. Du mußt nicht einmal zwingend von irgendeiner Klasse erben, Du mußt nur die paar benötigten Methoden zur Verfügung stellen.

        Tie::ExtraHash ist als blessed Array Reference implementiert, bei der das erste Array-Element (Index 0) eine Hash-Referenz enthält, aus der die in Tie::ExtraHash definierten Methoden die normale Funktion eines Hashes nachbauen. Die restlichen Elemente des Arrays stehen zur freien Verfügung. Dort könntest Du z.B. ein Filehandle ablegen.

        Es ist nicht einmal notwendig, dass Du im Inneren des Objekts überhaupt irgendwelche Daten speicherst. In Deinem Beispiel könntest Du den Filehandle selbst als Objekt benutzen (blessed Glob Reference à la IO::Handle), oder (für etwas leichter lesbaren Code) als erstes und einziges Element in eine blessed Array Reference packen. Jeder Zugriff auf den tied Hash würde dann direkt zu Dateizugriffen führen. Mit Storable ist der Zugriff auf einzelne Hash-Elemente allerdings nicht sonderlich einfach (weil nicht vorgesehen). Letztlich müßtest Du jedes mal eine temporäre Variable mit dem gesamten, deserialisierten Dateiinhalt füllen.

        Würdest Du stattdessen den Hash in einer primitiven SQLite-Tabelle vorhalten (und die Werte auf Strings beschränken), wäre es problemlos möglich, im Objekt nur ein DBI-Connection-Handle zu halten, das STORE() via insert/update, FETCH() via select, EXISTS() und SCALAR() via select count(*), DELETE() und CLEAR() via delete implementiert. Für FIRSTKEY()/NEXTKEY() müßtest Du entscheiden, ob Du beim Aufruf von FIRSTKEY() einmalig alle Keys in ein Hilfsarray ziehst oder ein DBI-Statement-Handle aktiv läßt; das dürfte vom Umfang der Tabelle abhängen. Bei einer Arrayref-basierenden Implementierung böte es sich an, das Connection-Handle im Index 0 zu halten und je nach Lösungsweg entweder das Statement-Handle im Index 1 oder ab Index 1 temporär alle gelesenen Keys. Wahlweise natürlich auch in Index 1 eine Arrayref mit allen Keys.

        Um noch einmal auf die Klasse zurückzukommen, die den tied Hash implementiert: Du mußt wie gesagt nicht von einer "magischen" Klasse erben, Du kannst, wenn es Dir hilft, von JEDER Klasse erben. IO::Handle und die davon abgeleitete IO::File-Klasse implementieren die für tied Hashes notwenigen Methoden nicht, aber sie bieten alles, was Du brauchst, um ein Dateihandle in ein Objekt zu verpacken. Wenn Du also Deine tied-Hash-Klasse von IO::File erben läßt und einfach nur die tied-Hash-Methoden hinzufügst, bekommst Du automatisch ein Objekt, dass ein Dateihandle beinhaltet. Eigene Objekt-Attribute kannst Du beliebig hinzufügen, das ist z.B. in IO::Socket zu sehen, die Konventionen sind in IO::Handle dokumentiert.

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
        1. Moin,

          Fang mal RTFM mit Tie::ExtraHash an.

          Meine Frage war an Dich gerichtet, ob _DU_ einen Filehandle in einen %hash tun würdest, der an eine Klasse gebunden ist.

          Hotti

          1. Moin Moin!

            Moin,

            Fang mal RTFM mit Tie::ExtraHash an.

            Meine Frage war an Dich gerichtet, ob _DU_ einen Filehandle in einen %hash tun würdest, der an eine Klasse gebunden ist.

            Lies den Rest meines Postings, wenn Du willst, dass das Objekt hinter dem Hash ein Filehandle enthält. Bei Deinem Ansatz, mit dem tied Hash eine Datei auf der Platte zu repräsentieren, ohne außerhalb der Klasse mit File-I/O und Serialisierung herumwerkeln zu müssen, wäre das u.U. sinnvoll; alternativ speicherst Du hinter den Kulissen einen Dateinamen (möglichst absolut, um Problemen mit chdir() aus dem Weg zu gehen).

            Wenn ich nach dem Wortlaut Deines Satzes gehe, lese ich $hash{'key'}=$handle. Das, also ein Filehandle in einen Hash zu packen, ist gelegentlich sinnvoll, so lange der Hash im Programm bleibt. Eine Serialisierung ist in der Regel nicht sinnvoll, weil eine neue Programminstanz mit dem deserialisierten Handle nichts anfangen kann.

            Alexander

            --
            Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so".
            1. hi,

              Wenn ich nach dem Wortlaut Deines Satzes gehe, lese ich $hash{'key'}=$handle. Das, also ein Filehandle in einen Hash zu packen, ist gelegentlich sinnvoll, so lange der Hash im Programm bleibt.

              Ja, der letzte Teilsatz ist der Knackpunkt. Als ich vor über einem Jahr mit Tied::Hash begann, hatte ich die verwegensten Datenstrukturen. Geht ja auch alles, aber es hat viele Seiteneffekte wenn in einer Datenstruktur neben Nutzdaten programmrelevante Teile rumliegen.

              Viele Grüße,
              Hotti