Bine: seek-Aufruf wird ignoriert

Hallo Leute,

ich versuch verzweifelt, meinem Skript beizubringen, wie es Werte in eine Datei schreiben soll. Im Endeffekt soll eine Art Tabelle rauskommen. Ich such mir Werte aus verschiedenen Dateien raus und setz dann einen Zähler, der bestimmt, wo der Wert hingeschrieben werden soll.

open(OUTPUT, $output);
seek (OUTPUT, $c, 0);
print OUTPUT @write;
close(OUTPUT);

$output ist als append eingestellt. Der schreibt aber alles untereinander, unabhängig davon, wo der Zähler ($c - der funktioniert) steht. Hat jemand ne Ahnung, woran das liegen könnte? Hab auch schon probiert, statt $c nen festen Wert einzusetzen, aber der reagiert überhaupt nicht darauf. In einem anderen Skript mit den selben Systemvoraussetzungen funktioniert's aber.
Und wie schreib ich am besten die Werte raus, damit OpenOffice Calc die als Tabelle interpretieren kann? Momentan trenn ich sie mit tab und schreib's als cvs raus. Ich hab von Perl leider nur ein bisschen Ahnung, hab das letzte Mal vor Urzeiten damit programmiert.

Danke!
Bine

  1. Hell-O!

    open(OUTPUT, $output);
    seek (OUTPUT, $c, 0);
    print OUTPUT @write;
    close(OUTPUT);

    Sieht erstmal gut aus.

    $output ist als append eingestellt.

    Du meinst so, wie es in perlopentut beschrieben ist? Welchen Modus hast du angegeben?

    Der schreibt aber alles untereinander, unabhängig davon, wo der Zähler ($c - der funktioniert) steht.

    Was wird untereinander geschrieben? Bedenke, dass seek() nur der Positionierung des Dateizeigers dient, Platz für einen neuen Eintrag schafft er nicht. Und schließlich: Wie ermittelst du $c?

    Hat jemand ne Ahnung, woran das liegen könnte? Hab auch schon probiert, statt $c nen festen Wert einzusetzen, aber der reagiert überhaupt nicht darauf. In einem anderen Skript mit den selben Systemvoraussetzungen funktioniert's aber.

    Du solltest ein bisschen mehr von deinem Script offenbaren, so kannman dir nicht helfen, nur raten.

    Und wie schreib ich am besten die Werte raus, damit OpenOffice Calc die als Tabelle interpretieren kann? Momentan trenn ich sie mit tab und schreib's als cvs raus.

    Mal ein ganz simples Beispiel:

    #!/usr/bin/perl -w  
      
    use strict;  
    use warnings;  
    use CGI::Carp qw(fatalsToBrowser);  
    use Fcntl qw(:flock);  
      
    my $file = "../daten.txt";  
      
    while(<DATA>) {  
      chomp($_);  
      my @words = split(/ /, $_);  
      open(FH, "+>>$file") || die $!;  
      flock(FH, LOCK_EX);  
      print FH join(';', @words) . "\n";  
      close(FH);  
    }  
      
    print "Content-type: Text/plain\n\n";  
    open(FH, $file) || die $!;  
    while(<FH>) {  
      print $_;  
    }  
    close(FH);  
      
    __DATA__  
    Ein kleiner Text anstatt einer Datei zum testen  
    Ich bin gespannt ob das auch funktioniert
    

    Das funktioniert ordnungsgemäß.

    Siechfred

    1. Moin,

      $output ist als append eingestellt.

      Umsetzung siehe unten

      Der schreibt aber alles untereinander, unabhängig davon, wo der Zähler ($c - der funktioniert) steht.
      Was wird untereinander geschrieben? Bedenke, dass seek() nur der Positionierung des Dateizeigers dient, Platz für einen neuen Eintrag schafft er nicht. Und schließlich: Wie ermittelst du $c?

      also eigentlich verarbeitet der mehrere Ausgangsdateien. Aus der ersten zieht er einen Wert und die Zeilennamen, für die anderen Dateien soll er die Werte nur den Zeilen zuordnen und hinten anhängen. Er schreibt die Werte aber unter die letzte Zeile.

      Du solltest ein bisschen mehr von deinem Script offenbaren, so kann man dir nicht helfen, nur raten.

      Findet mein Chef sicher nicht so toll... Trotzdem, ich muss ja weiter kommen:

      das Teil soll aus einem Quelltext Variablen und die dazugehörigen Werte rausschreiben

      #!/usr/bin/perl

      $length=1;
      $counter=0;    # zählt die Dateien

      $output=">>params.cvs";

      while ($length>0)
      {
        $file=sprintf("*Pfad, Dateinamen unterscheiden sich durch Zähler*",$counter);

      open(INPUT, $file);  #Einlesen der Quelldatei (Quelltext)
        @List = <INPUT>;
        close(INPUT);

      $end=1;  # dient als Abbruchbedingung, weil ich nur einen Teil des
                   Textes einlesen will
        $c=0;    # zählt die rausgeschriebenen Variablen

      $length=@List;   # weil ich nicht genau weiß, wieviele Dateien
                           dieses Typs ich einlesen will, stell ich so
                           fest, ob die Datei leer ist. Wenn ja, hör ich
                           auf mit dem Programm (sind aufsteigend
                           nummeriert)

      foreach $File(@List)
        {
          $sigs="";
          if (index($File,"*** GUI ***")>=0)   #ab dieser Textstelle brauch
                                                ich nix mehr auswerten->
                                                Abbruch (if-Anweisung unten
                                                wird nicht mehr ausgeführt)
          {
            $end=0;
          }

      if ((index($File,"#define")>=0)&&($end>0))  #mein Schlagwort,
                                                       dahinter steht das,
                                                       was ich suche
          {
      #jetzt wird's ziemlich chaotisch. Die Trennung ist hier durch Leerzeichen umgesetzt, die kann ich aber nicht vernünftig verarbeiten, auch weil es immer eine unterschiedliche Anzahl ist. Deswegen ersetz ich alle durch Ä's (die kommen in der Datei nicht vor) und fasse dann Ä's zu einem eindeutigen Trennzeichen zusammen (ÄÄÄ). Ich weiß, ist alles andere als ne Ideallösung, aber es geht (ich sagte ja, ich hab nicht viel Ahnung!)

      $l=length($File);
           my @sign;
           for(my $i=0; $i<$l; $i++)
            {
              $h=substr($File,$i,1);
       if ($h ne " ")
       {
                @sign[$i]=$h;
       }
       else
       {
         @sign[$i]='Ä';
              }
            $sigs=sprintf("%s%s",$sigs,@sign[$i]);
            }

      $sigs=~ s/\t+/ÄÄÄ/g;    # ab und zu kommen auch mal Tabs als
                                      Trennzeichen vor
            $sigs=~ s/Ä+/ÄÄÄ/g;

      @tmp=split(/ÄÄÄ/,$sigs);
            # in $tmp[1] steht der Name der Variablen, in $tmp[2] der Wert,
              den ich suche

      if (index($tmp[2],"(")<0)   # Werte in Klammern brauch ich
                                           nicht
            {
              $c++; # zählt die Variablen und wird nach Ende der Datei
                      wieder auf Null gesetzt
              if ($counter==0)        # Name mit in Zeile schreiben
              {
                @write=($tmp[1],' ', $tmp[2],"\n");
              }
              else
              # weil's in der Zeile angefügt werden soll, brauch ich ab der
                zweiten Datei den Namen nicht mehr
              {
                @write=(" ",$tmp[2]);
              }

      # und jetzt kommt das berühmte seek...
       open(OUTPUT, $output);
              seek (OUTPUT, $c, 0);
       print OUTPUT @write;
              close(OUTPUT);

      }
          }
        }
        $counter++;
      }

      Hmmm, hilft das jetzt weiter?

      Mal ein ganz simples Beispiel

      Ich bin am Ausprobieren, will aber noch nicht so richtig. Ich geb dann Bescheid. Das seek geht aber nach wie vor nicht.

      Trotzdem schonmal danke für deine Hilfe!
      Bine

      1. Hell-O!

        also eigentlich verarbeitet der mehrere Ausgangsdateien. Aus der ersten zieht er einen Wert und die Zeilennamen, für die anderen Dateien soll er die Werte nur den Zeilen zuordnen und hinten anhängen.

        Du hast also eine bzw. mehrere Dateien, die dir sagen, welche Dateien du verarbeiten sollst, das Dateinamenschema steht fest? Dann wäre dein Code ziemlich umständlich. Entweder du setzt das Standardmodul File::Find ein oder programmierst das Ganze zu Fuß. Letzteres könnte so aussehen:

        # Array für die Quelldateien  
        my @infiles;  
        # Pfad zu den Quelldaten  
        my $sourcedir = '/pfad/zu/deinen/daten/';  
        # Suchmuster für die Quelldateien  
        # Mein Schema: datei_00.dat  
        my $pattern = 'datei_\d{2}\.dat';  
          
        opendir(DIR, $sourcedir) || die "Could not read $sourcedir: $!";  
        @infiles = grep { /^$pattern$/ } readdir(DIR);  
        closedir(DIR);
        

        Im Ergebnis stehen im Array @infiles alle Dateien, die ihrerseits Dateilisten enthalten. Die kannst du jetzt nacheinander öffnen und abfragen, indem du sie mit einer foreach-Schleife durchgehst:

        my @sourcefiles;  
          
        foreach(@infiles) {  
          open(FH, "$_") || die "Could not open $_: $!";  
          flock(FH, 1);  
          while(<FH>) {  
            chomp $_;  
            push @sourcefiles, $_;  
          }  
        }
        

        Jetzt hast du alle Quelldateien in deinem Array @sourcefiles. Dieses gehst du wieder mit einer foreach-Schleife durch, extrahierst die Daten, die du brauchst und schreibst sie gleich weg, so wie ich es in meinem simplen Beispiel geschrieben habe. Übrigens solltest du beim Steuern des Auslesevorgangs mal über die Verwendung von continue, next und last nachdenken.

        und jetzt kommt das berühmte seek...

        Ich sehe nicht, wofür du das seek brauchst.

        Siechfred

      2. das Teil soll aus einem Quelltext Variablen und die dazugehörigen Werte rausschreiben

        #!/usr/bin/perl

        Ich würde dir dringend zu use strict und -w (Warnungen) raten. Es gibt viele Fehler, die du so nie finden wirst.
        Gerade wenn du dabei bist etwas zu entwickeln sind die Warnungen und Fehlermeldungen von Perl extrem hilfreich.

        open(INPUT, $file);  #Einlesen der Quelldatei (Quelltext)

        Besser:
        open(INPUT, $file) or die "Kann $file nicht öffnen: $!";

        $length=@List;   # weil ich nicht genau weiß, wieviele Dateien
                             dieses Typs ich einlesen will, stell ich so
                             fest, ob die Datei leer ist. Wenn ja, hör ich
                             auf mit dem Programm (sind aufsteigend
                             nummeriert)

        Um festzustellen ob eine Datei leer ist kannst du z.b. -s benutzen

        # und jetzt kommt das berühmte seek...
        open(OUTPUT, $output);

        Hier öffnest du die Datei zum lesen und dann ...

        seek (OUTPUT, $c, 0);
        print OUTPUT @write;

        ... willst du sie beschreiben.
        Hättest du die Warnungen angeschaltet, hättest du folgenden Output bekommen:
        Filehandle main::OUTPUT opened only for input at test.pl line X.

        Eine Datei lesen und beschreiben geht mit "+<" oder '+>>', aber vorsicht lesen und schreiben von Dateien ist voller Fallstricke.

        Struppi.

        1. Hallo,

          Ich würde dir dringend zu use strict und -w (Warnungen) raten. Es gibt viele Fehler, die du so nie finden wirst.

          ist mittlerweile eingebaut, was ich geposted hab, war mein erstes Testskript (musste schnell gehen :,) )

          Gerade wenn du dabei bist etwas zu entwickeln sind die Warnungen und Fehlermeldungen von Perl extrem hilfreich.

          stimmt

          open(OUTPUT, $output);
          Hier öffnest du die Datei zum lesen und dann ...

          nee, zum schreiben, hab $output oben als ">>dateiname" deklariert
          Hab aber mittlerweile die Vorschläge von Siechfred eingebaut und jetzt ist Perl ganz friedlich.

          Danke für eure Hilfe, mein Skript spuckt jetzt brav so ne Art Tabelle aus. Habt mich vorm Chef gerettet... :,)

          Grüße
          Bine