Stefan Muenz: Betriebssystemunabhaengige File-Copy-Funktion

Liebe Forumsbesucher,

heute mal eine Fachfrage von mir:
ich suche in Perl eine Funktion zum Kopieren von Dateien. Dabei will ich system-calls vermeiden, weil das Ganze BS-unabhaengig sein soll.
Nun gibt es da noch die Scheinkopier-Funktion link($oldfile,$newfile), doch die wird offensichtlich auch nur von Unix-Plattformen unterstuetzt, wo es "link" ja auch als Betriebssystem-Kommando gibt. Unter Windows jedenfalls brachte mir die link-Funktion in Perl einen CGI-Error.

Gibt es noch eine andere Funktion? Oder muß man alle betroffenen Dateien (in diesem Fall: diverse Grafiken) binaer einlesen und unter neuem Namen wieder zurueckschreiben?

viele Gruesse
  Stefan Muenz

  1. Hi Stefan,

    heute mal eine Fachfrage von mir:

    muß ja auch mal sein :-)

    ich suche in Perl eine Funktion zum Kopieren von Dateien. Dabei will ich system-calls vermeiden, weil das Ganze BS-unabhaengig sein soll.
    Nun gibt es da noch die Scheinkopier-Funktion link($oldfile,$newfile), doch die wird offensichtlich auch nur von Unix-Plattformen unterstuetzt, wo es "link" ja auch als Betriebssystem-Kommando gibt. Unter Windows jedenfalls brachte mir die link-Funktion in Perl einen CGI-Error.

    Gibt es noch eine andere Funktion? Oder muß man alle betroffenen Dateien (in diesem Fall: diverse Grafiken) binaer einlesen und unter neuem Namen wieder zurueckschreiben?

    Es gibt eine einfache Lösung: das Modul File::Copy! Folgende Syntax:

    use File::Copy;
    copy("file1", "file2");

    File::Copy ist standardmäßig vorhanden bzw. kann mit Sicherheit bei http://www.perl.com/CPAN/ runtergeladen werden und hat den Vorteil, sich um die ganzen Betriebssystem-Sachen zu kümmern. Funktioniert sogar mit OS/2 :-)

    Erweiterte Syntax:
    copy("file1", "file2") or die "Fehler: $!";
    Dadurch wird die Fehlermeldung des Systems abgefangen und ausgegeben (ins Errorlog).

    Cheatah

    1. hye ihr 2 :-)

      Es gibt eine einfache Lösung: das Modul File::Copy! Folgende Syntax:

      use File::Copy;
      copy("file1", "file2");

      das mit dem modul hast ja du schon erleutert cheatah. brauche ich also nicht mehr zu machen
      *da hät ich wieder mal ne antwort gewusst, und dann bin ich zu langsam :-/*

      aber: zum befehl 'link'....
      unter win98 funtioniert dieser befehl bei mir!!!!
      (mit dem sambar server)

      mfg
      BOGUS

      1. Hallo Bogus

        aber: zum befehl 'link'....
        unter win98 funtioniert dieser befehl bei mir!!!!
        (mit dem sambar server)

        Interessant! Ich hab es mit Win95 und Xitami probiert. Und da erzeugte dieser Befehl einen Eintrag im CGI-Error-File des Servers, und das Script wurde nicht mehr weiter ausgefuehrt. Wie sehen denn die Link-Dateien hinterher aus? Sind das echte Kopien, oder Windows-lnk-Dateien, oder was?

        viele Gruesse
          Stefan Muenz

        1. Hallo Bogus

          aber: zum befehl 'link'....
          unter win98 funtioniert dieser befehl bei mir!!!!
          (mit dem sambar server)

          Interessant! Ich hab es mit Win95 und Xitami probiert. Und da erzeugte dieser Befehl einen Eintrag im CGI-Error-File des Servers, und das Script wurde nicht mehr weiter ausgefuehrt. Wie sehen denn die Link-Dateien hinterher aus? Sind das echte Kopien, oder Windows-lnk-Dateien, oder was?

          viele Gruesse
            Stefan Muenz

          Hye Stefan,

          weil du nachgefragt hast, hab ich mir das ganze nochmal angesehen. Ich war der Meinung ich hätte den 'link' befehl in meinen scripts verwendet. war ein irrtum: der befehl 'unlink' funktioniert bei mir.

          'link' habe ich versucht,....da tut sich bei mir garnichts. sorry!

          cu
          BOGUS

    2. Hallo Cheatah,

      use File::Copy;
      copy("file1", "file2");

      Prima! Tja, muss mich halt doch mal mehr mit diesen ollen Modulen beschaeftigen. Das Problem, das zu meiner Frage fuehrte, hab ich zwar mittlerweile ganz anders geloest, aber trotzdem bin ich mal wieder ein wenig schlauer :-)

      viele Gruesse
        Stefan Muenz

      1. Hi Stefan,

        use File::Copy;
        copy("file1", "file2");

        Prima! Tja, muss mich halt doch mal mehr mit diesen ollen Modulen beschaeftigen. Das Problem, das zu meiner Frage fuehrte, hab ich zwar mittlerweile ganz anders geloest, aber trotzdem bin ich mal wieder ein wenig schlauer :-)

        tja, ich mußte mich zu Modulen auch erst "bekehren" lassen. Zwar benutze ich sie immer noch praktisch nicht (GD.pm für Grafik, mittlerweile CGI.pm, um die Parameter auszulesen), aber immerhin weiß ich, daß sie gerade für allgemeingültige Funktionen ideal sind.

        Übrigens hilft de.comp.lang.perl.misc (ehemals de.comp.lang.perl) und de.comp.lang.perl.cgi dabei; manchmal ist man erstaunt, für was für Anwendungen es alles schon fertige Module gibt, mit denen man ein fehleranfälliges x*100-Zeilen-Script mit drei kurzen Befehlen erstellen kann!

        Ich mache trotzdem potentiell meine Dinge selbst, da weiß ich wenigstens, was ich falsch mache :-)

        Cheatah

        1. Hallo Cheatah,

          Ich mache trotzdem potentiell meine Dinge selbst, da weiß ich wenigstens, was ich falsch mache :-)

          Tja, das ist in Perl wie anderswo immer so eine Gratwanderung. Ich selber neige bei allem rund ums Web-Publishing auch dazu, die Dinge umstaendlicher anzugehen, aber dafuer zu wissen, was ich getan habe, als mich auf etwas zu verlassen, dessen Funktionalitaet ich nicht genau kenne. Aber bei anderen Sachen bin ich eher das Gegenteil. Es interessiert mich z.B. nicht die Bohne, wie viele technische Dinge in Haushalt und Arbeit funktionieren, ich benutze sie einfach und lass sie reparieren wenn sie kaputt sind. Sogar bei PC-Hardware geht mir das schon so. Ich kann mich einfach nicht dafuer begeistern, es interessiert mich nicht bzw. nur so weit, wie es fuer meine Software-Interessen von Belang ist. Ich will es einfach nur nutzen. Da bin ich der totale "Wysiwyg-Typ". Nur bei HTML, JS, CSS, Perl usw., da mutiere ich dann ploetzlich zum Hardcore-Hardcoder ;-)

          viele Gruesse
            Stefan Muenz

          1. Hi Stefan,

            Tja, das ist in Perl wie anderswo immer so eine Gratwanderung. Ich selber neige bei allem rund ums Web-Publishing auch dazu, die Dinge umstaendlicher anzugehen, aber dafuer zu wissen, was ich getan habe, als mich auf etwas zu verlassen, dessen Funktionalitaet ich nicht genau kenne. Aber bei anderen Sachen bin ich eher das Gegenteil. Es interessiert mich z.B. nicht die Bohne, wie viele technische Dinge in Haushalt und Arbeit funktionieren, ich benutze sie einfach und lass sie reparieren wenn sie kaputt sind. Sogar bei PC-Hardware geht mir das schon so. Ich kann mich einfach nicht dafuer begeistern, es interessiert mich nicht bzw. nur so weit, wie es fuer meine Software-Interessen von Belang ist. Ich will es einfach nur nutzen. Da bin ich der totale "Wysiwyg-Typ". Nur bei HTML, JS, CSS, Perl usw., da mutiere ich dann ploetzlich zum Hardcore-Hardcoder ;-)

            ich stelle hiermit offiziell fest, daß wir seelenverwandt sind :-) Mein Wasserkocher und auch die SCSI-Karte sind mir eigentlich völlig egal, die will ich nur benutzen, deshalb haben sie zu funktionieren. Das "wie" ist nicht mein Problem. Was ich aber anderen anbiete, ist absolut mein Problem, deswegen muß und will ich verstehen, was da im einzelnen vor sich geht.

            Bei Modulen ist das in der Tat eine Gratwanderung, weil ich die Scripte anwende, ohne sie inhaltlich zu verstehen (obwohl der Quellcode ja gewöhnlich offenliegt). Dennoch, die Programmierer haben sich dabei eine Menge gedacht, sie haben alle möglichen Fälle in Betracht gezogen (zumindest bei den Standardmodulen), deswegen funktionieren sie. Gerade bei solchen Dingen wie Parameterabfrage ist es einfacher, per

            use CGI;
            $data = new CGI;
            @multiples = $data->param("auswahl");

            alle angewählten Optionen eines Mehrfachauswahl-Feldes einzulesen, als mit irgendeinem "hingepfuschten" Script nur das letzte ausgewählte Element zu erhalten oder bei einem etwas besseren Script alle durch z.B. ":" getrennt - egal ob in den einzelnen Elementen vielleicht das gleiche Zeichen vorkommt oder nicht. Module haben schon ihre Vorteile...

            Cheatah

            1. Moin Cheatah!

              ...
              Standardmodulen), deswegen funktionieren sie. Gerade bei solchen Dingen wie Parameterabfrage ist es einfacher, per

              use CGI;
              $data = new CGI;
              @multiples = $data->param("auswahl");

              alle angewählten Optionen eines Mehrfachauswahl-Feldes einzulesen, als mit irgendeinem "hingepfuschten" Script nur das letzte ausgewählte Element zu erhalten

              Da hast Du wohl recht, und ich finde es auch anstrengend, immer zwischen Put/Get, Multipart usw. "zu Fuß" unterscheiden zu müssen. Andererseits - die Datei cgi.pm ist z.B. 193 kB und deutlich über 6000 Zeilen lang. Damit ist Perl unter Win95 schon einige Sekunden lang beschäftigt, bevor was passiert. Für einfache Kontaktformulare mag das ja gehen, aber für eine GUI wird es z.B. nervig. Weißt Du, ob es da noch einen anderen Weg gibt (evtl. irgendeine Precompile-Möglichkeit, die ich noch nicht mitbekommen habe?!)?

              Bis dannundwann!

              Andreas Bierhals

              1. Hi,

                use CGI;

                Da hast Du wohl recht, und ich finde es auch anstrengend, immer zwischen Put/Get, Multipart usw. "zu Fuß" unterscheiden zu müssen. Andererseits - die Datei cgi.pm ist z.B. 193 kB und deutlich über 6000 Zeilen lang. Damit ist Perl unter Win95 schon einige Sekunden lang beschäftigt, bevor was passiert. Für einfache Kontaktformulare mag das ja gehen, aber für eine GUI wird es z.B. nervig. Weißt Du, ob es da noch einen anderen Weg gibt (evtl. irgendeine Precompile-Möglichkeit, die ich noch nicht mitbekommen habe?!)?

                nicht daß ich wüßte, aber ein vernünftig ausgelasteter Server sollte das Modul genau wie den Perl-Interpreter eigentlich im Speicher halten.

                Cheatah

              2. hi!

                die Datei cgi.pm ist z.B. 193 kB und deutlich über 6000 Zeilen lang. Damit ist Perl unter
                Win95 schon einige Sekunden lang beschäftigt, bevor was passiert. Für einfache
                Kontaktformulare mag das ja gehen, aber für eine GUI wird es z.B. nervig. Weißt Du, ob es
                da noch einen anderen Weg gibt (evtl. irgendeine Precompile-Möglichkeit, die ich noch nicht
                mitbekommen habe?!)?

                Unter Apache gibt es mod_perl. Perl-Skripts, die darauf basieren, bleiben die ganze Zeit im Speicher.

                bye, Frank!

  2. Hallo Stefan!

    ich suche in Perl eine Funktion zum Kopieren von Dateien. Dabei will ich system-calls vermeiden, weil das Ganze BS-unabhaengig sein soll.

    Da setze ich gleich noch einen drauf: Mich interessiert das aktuelle Verzeichnis. Ich habe weder eine pwd-Funktion in Perl gefunden noch eine vordefinierte Variable. Also koennte man ja Kommandosubstitution versuchen:
    $pwd = pwd;
    Aber: Unter Windows und aehnlichem heisst es nicht pwd, sondern cd. Ausserdem hat der IIS4 ein Problem mit der IO-Redirection, sodass die Kommandosubstitution dort nicht immer funktioniert (siehe <../../sfarchiv/1999_2/t02844.htm> und <../../sfarchiv/1999_2/t03170.htm>).
    Was also tun? Gibt es da auch irgendein Modul, in dem das beinhaltet ist?

    Bye by Calocybe

    1. Hi,

      Da setze ich gleich noch einen drauf: Mich interessiert das aktuelle Verzeichnis. Ich habe weder eine pwd-Funktion in Perl gefunden noch eine vordefinierte Variable. Also koennte man ja Kommandosubstitution versuchen:
      $pwd = pwd;

      ich bin nicht ganz sicher, aber unter

      use File::Basename;

      finde ich die Funktion dirname(), die den Verzeichnisnamen einer Datei liefern soll. Teste das doch mal mit

      print dirname(".");

      oder dito mit "./", "./*" etc. Ich denke, das sollte klappen. Ansonsten such doch mal bei http://www.perl.com/CPAN/ danach.

      Cheatah

      1. Hallo Cheatah!

        print dirname(".");

        Nee, das war's leider nicht. Dies scheint eine reine Stringparsing-Funktion zu sein, die sich nicht um die realen Gegebenheiten kuemmert. Sie scheint einfach den Verzeichnisanteil eines Dateipfades zu extrahieren. Fuer dirname("datei.ext") kommt einfach . heraus. Im Modul steht dann auch fuer DESCRIPTION:
        These routines allow you to **parse** file specifications into useful
        pieces using the syntax of different operating systems.

        Ansonsten such doch mal bei http://www.perl.com/CPAN/ danach.

        Ok, aber heute nicht. *g* (War mir nur gerade so eingefallen, ist kein dringendes Problem.)

        Bye by Calocybe

        1. Hi,

          print dirname(".");

          Nee, das war's leider nicht. Dies scheint eine reine Stringparsing-Funktion zu sein, die sich nicht um die realen Gegebenheiten kuemmert. Sie scheint einfach den Verzeichnisanteil eines Dateipfades zu extrahieren. Fuer dirname("datei.ext") kommt einfach . heraus. Im Modul steht dann auch fuer DESCRIPTION:
          These routines allow you to **parse** file specifications into useful
          pieces using the syntax of different operating systems.

          hm, naja, war auch einfach ins Blaue geraten :-) Vielleicht gibt es in den Standardmodulen noch irgendwo eine Lösung dazu, ich werde bei Gelegenheit mal suchen gehen.

          Ansonsten such doch mal bei http://www.perl.com/CPAN/ danach.

          Ok, aber heute nicht. *g* (War mir nur gerade so eingefallen, ist kein dringendes Problem.)

          Oki :-)

          Cheatah

    2. hi!

      Da setze ich gleich noch einen drauf: Mich interessiert das aktuelle Verzeichnis. Ich habe
      weder eine pwd-Funktion in Perl gefunden noch eine vordefinierte Variable.

      $0 liefert den Dateinamen des Skripts. Vielleicht wird dabei auch der Pfad mit übergeben? Müsste man mal ausprobieren...

      bye, Frank!

      1. Hi Frank!

        $0 liefert den Dateinamen des Skripts. Vielleicht wird dabei auch der Pfad mit übergeben? Müsste man mal ausprobieren...

        Die Idee ist gut, aber es ist ja nicht gesagt, dass das Script in seinem Verzeichnis gestartet wird. Der IIS von M$ hat da z.B. ein paar Eigenarten. Er *scheint*, das Script immer in dem Verzeichnis zu starten, welches das oberste im aktuellen *virtuellen* Verzeichnis ist. Beispiel: Ich habe zwei virtuelle Verzeichnisse:
        /           -->    c:\www\root
        /cgi-bin    -->    c:\www\cgi
        Wenn ich jetzt http://x.y.z/cgi-bin/foo/foo.pl aufrufe, dann ist das aktuelle Verzeichnis des Scripts nicht etwa c:\www\cgi\foo, sondern c:\www\cgi. Wie gesagt, es *scheint* so zu sein, ich bin damals dem Phaenomen nicht weiter nachgegangen, weil es fuer mein aktuelles Problem nicht relevant war und ich auch nicht den Ehrgeiz habe, alles ueber den IIS herauszufinden.

        Wie auch immer, $0 liefert bei mir (ActivePerl auf WinNT4) immer den vollen Pfad zum Script in MS-Schreibweise, also I:\files\perl\script_path.pl, egal ob ich das Script mit ..\script_path.pl oder /files/perl/script_path.pl aufgerufen habe. Man koennte also $0 hernehmen, den Dir-Anteil rausholen (das dann mit dirname() aus File::Basename), und das dann an chdir() uebergeben, falls das eigentliche Problem darin besteht, dass das Script im aktuellen Verzeichnis liegt.

        Bye by Calocybe

      2. $0 liefert den Dateinamen des Skripts. Vielleicht wird dabei auch der Pfad mit übergeben? Müsste man mal ausprobieren...

        Zu $0 gibt es eine "offizielle" Alternative aus den Modulen zu ActivePerl (meine Version ist 5.005 build 509):

        use FindBin;
        my $local = $FindBin::Bin;

        Dann ist $local das Verzeichnis, in dem das ausgeführte Programm gespeichert ist.