Perl Module (und filehandle)

Liebe® Perl Experte/in,

ich habe eine Frage zu Perl-Modulen: Ich habe mehrere Scripte, die auf den gleichen Satz von log-Funktionen zugreifen. Ein Minimal-Beispiel für den Hauptteil einer solchen Datei ist:

sub hw{
print LOG „Hello, World!\n“;
}

open(LOG, „> test.txt“);
hw();
close(LOG);

Um Redundanz zu vermeiden und die Veränderung dieser log-Funktionen zu vereinfachen, würde ich sie jedoch gerne in ein Modul auslagern. Wenn ich mich richtig informiert habe, erstelle ich so das Modul:

package MyModule;
use strict;
use Exporter;
our $VERSION = 1.00;
our @ISA = qw(Exporter);
our @EXPORT = qw(hw);

sub hw{
print LOG „Hello, World!\n“;
}

1;

Und binde es so im Hauptprogramm ein:

use MyModule;

open(LOG, „> test.txt“);
hw();
close(LOG);

Das liefert mir jedoch den folgenden Fehler:

print() on unopened filehandle LOG at MyModule.pm line 10.

Meine Frage ist nun: Kann ich mein filehandle irgendwie an das Modul weiterreichen? (filehandles sind für mich irgendwie komische Objekte in Perl, die ich grundsätzlich nicht so recht verstehe…)

Ein anderer Ansatz ist natürlich, die Verwaltung der filehandles komplett dem Modul zu übertragen, d.h. open(LOG, „> test.txt“); und close(LOG) nur aus dem Modul heraus aufzurufen. Aber ich frage mich trotzdem, ob es für den anderen Ansatz gar keine Lösung gibt.

Vielen Dank für Ihre Hilfe!
Schöne Grüße,

Manfred

Meine Frage ist nun: Kann ich mein filehandle irgendwie an das
Modul weiterreichen? (filehandles sind für mich irgendwie
komische Objekte in Perl, die ich grundsätzlich nicht so recht
verstehe…)

Ich würde einfach mal versuchen, dass Filehandle einfach per Parameter hw(LOG) zu übergeben und dann zu benutzen:

sub hw{
my $FILE = shift;
print $FILE „Hello, World!\n“;
}

Aber ich bin auch nicht sicher, ob man das mit Filehandles machen darf. Ansonsten ist beste Weg sicherlich, den Dateinamen als Parameter zu übergeben und die Subroutine die Datei öffnen zu lassen. Desweiteren kannst du auch z.B. noch den zu loggenden Text als zweiten Parameter übergeben.

hw(„test.txt“);

sub hw{
my $file= shift;
open(LOG, „> $file“);
print LOG „Hello, World!\n“;
close(LOG);
}

Gruß, Norbert

Hallo Manfred.

Zum ersten: wenn Du ein Modul verwendest, ist es üblich, den Modulnamen mit anzugeben beim Aufruf, in Deinem Fall:
MyModule::hw();

Du kannst den Filehandler mit übergeben, dies sähe dann in etwa so aus:

sub hw{
$FILE=$_[1];
print $FILE „Hello, World!\n“;
}

Aufruf:
MyModule::hw(*FILE);

Der * benutzt den Mechnismuss „type globbing“ (* = Wildcard für alle anderen Präfix-Buchstaben wie $, %, &amp:wink:.

Einfach mal ausprobieren.

Viele Grüße,
Michael

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Norbert,

vielen Dank für Deine Antwort.

sub hw{
my $FILE = shift;
print $FILE „Hello, World!\n“;
}

Aber ich bin auch nicht sicher, ob man das mit Filehandles
machen darf.

Scheinbar nicht:

Can’t use an undefined value as a symbol reference at MyModule.pm line 11.

Darum sind filehandles für mich sehr komische Objekte…

Schöne Grüße,

Manfred

Moin,
eine einfache Moeglichkeit waere das Handle als Variable an das Modul zu uebergeben.

Dein Beispiel hab ich mal erweitert.

#!/usr/bin/perl
use strict;

my $log;
sub hw{
print $log „Hello, World!\n“;
}

open($log, „> test.txt“);
hw();
close($log);

So kannt du das Handle immer weitergeben oder auch in Arrays verwalten.

Hoffe ich konnte helfen.

MfG Freddy

Hallo Michael,

vielen Dank für Deine Antwort!

Zum ersten: wenn Du ein Modul verwendest, ist es üblich, den
Modulnamen mit anzugeben beim Aufruf, in Deinem Fall:
MyModule::hw();

Ich habe das so verstanden, daß ich mir das mit dem Exporter-Modul sparen kann, weil das den Namensraum des Moduls direkt in den Namensraum des aufrufenden Scripts exportiert.

Du kannst den Filehandler mit übergeben, dies sähe dann in
etwa so aus:

sub hw{
$FILE=$_[1];
print $FILE „Hello, World!\n“;
}

Aufruf:
MyModule::hw(*FILE);

Der * benutzt den Mechnismuss „type globbing“ (* = Wildcard
für alle anderen Präfix-Buchstaben wie $, %, &amp:wink:.

Saustark!
Das mit dem type globbing Mechanismus war mir gänzlich unbekannt, ich werde mich demnächst einmal genauer darüber informieren.
Die Logik der file handles verstehe ich allerdings immer noch nicht… muß aber auch nicht sein, ist ja Perl! :wink:

Schöne Grüße,

Manfred

Hallo Manfred,

Du musst Dir den Filehandler eben als Platzhalter für den (Datei-)Zugriff vorstellen.
Lesen: open (LESEN, " datei.txt");
Anhängen: open (APPEND, ">> datei.txt);
Lesen / Schreiben: open (RW, „+ datei.txt“);
Lesen / Schreiben / Anhängen / Anlegen: open (RWAC, „+>> datei.txt“);

Zugriff entweder wie oben (insbesondere beim Schreiben), beim Lesen zum Beispiel:
my $eingabe;
while ($eingabe=) { print $eingabe; }

Interessant vielleicht noch: willst Du von Stdin lesen, gibt es den so genannten Diamond-Operator:
Lesen von Stdin:
while ($eingabe=) …

Viele Grüße und viel Spaß mit Perl :wink:
Michael

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Manfred,

meines Wissens kannst Du ein Filehandle als Referenz (und nur als solche) an eine Funktion (sub) übergeben. Dabei spielt es keine Rolle ob sie im Programm selber oder in einem Modul befindet.
z.B. so

Aufruf:
hw(*LOG);

sub hw {
my $fh = shift;
print $fh „Hello, World!\n“;
}

Gruss Klaus

Hallo,

eine unschöne aber funktionierende Lösung:

sub hw{
print main::LOG „Hello, World!\n“;
}

Das ist die Vollständige Adressierung der Variable (Ein Filehandle ist auch nur eine Variable).

Gruß
Arne

Hallo Freddy,

vielen Dank für Deine Antwort!
Ich wußte nicht, daß man filehandles auch in ganz normale Skalare stecken kann. Klasse!

Schöne Grüße,

Manfred

Hallo Klaus,

vielen Dank für Deine Antwort! Filehandles per Referenz weiterzureichen scheint mir die sauberste Art zu sein. (Ich wäre nie darauf gekommen, daß man das mit * macht.)

Schöne Grüße,

Manfred

Hallo Arne,

vielen Dank für Deine Antwort.
Das ist auch ein guter Trick, den ich einmal ausprobieren muß.

Schöne Grüße,

Manfred

sorry, räume gerade auf, evtl. benötigst du noch eine
antwort. du übergibst einfach eine referenz auf das
filehandle!

script:
###################################
#!c:\perl\bin\perl.exe -w
use MyModule;

open(LOG, „> test.txt“);
hw(*LOG, „Hello World!\n“);
close(LOG);

exit;
################################

Module:
################################
package MyModule;
use strict;
use Exporter;
our $VERSION = 1.00;
our @ISA = qw(Exporter);
our @EXPORT = qw(hw);

sub hw{
my $fh = shift;
my $text = shift;
print $fh „$text“;
}

1;

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

Hallo Mathias,

du übergibst einfach eine referenz auf das filehandle!

Ja, das hatte auch Klaus S. schon vorgeschlagen; das scheint mir die sauberste Lösung zu sein.

Danke für Deine Antwort und schöne Grüße,

Manfred