opi: Pointer ans Ende der Datei setzen mit seek

Hallo,

gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer
Datei mit seek zu setzen oder muss ich die Datei zuerst komplett
durchlaufen?

Greez,
opi

--
Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
  1. Hallo,

    gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer
    Datei mit seek zu setzen oder muss ich die Datei zuerst komplett
    durchlaufen?

    Was genau hast du denn vor? Wenn du Daten dranhängen willst, wäre es nicht effizienter und sinnvoller, die Datei mit >> zu öffnen?

    Markus.

    --
    http://www.apostrophitis.at
    http://www.pithax.net
    Wenn ich ein toller Programmierer währe, könnte ich vieleicht sogar Packete nach einem gewissen Standart kompelieren...
    Vieleicht progge ich aber auch eine tolle Gallerie, die dann hoffentlich funzt.
    1. Hallo,

      gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer
      Datei mit seek zu setzen oder muss ich die Datei zuerst komplett
      durchlaufen?
      Was genau hast du denn vor? Wenn du Daten dranhängen willst, wäre es nicht effizienter und sinnvoller, die Datei mit >> zu öffnen?

      nicht in allen Fällen.
      Beispielsweise könnte man erst von einer bestimmten Stelle lesen wollen, danach am Ende schreiben.
      Das schließen und neu öffnen würde hier in allen Fällen länger dauern, zudem könnte man seinen <http://de.selfhtml.org/perl/funktionen/einausgabe.htm#flock@title=exklusiven Zugriff> verlieren.

      Während dem neu öffnen kann auch ein anderer Prozess Änderungen an der Datei vornehmen, was zu unerwarteten Ergebnisse führen kann. Das Resultat ist eine Sicherheitslücke. Ich empfehle mal nach "Race Condition" zu suchen.

      Gruß,
      Benne

      --
      ie:% fl:( br:> va:) ls:> fo:| rl:° ss:) de:[ js:| ch:| mo:} zu:)
  2. Tag opi.

    gibt es eine Möglichkeit, den Dateizeiger direkt ans Ende einer Datei mit seek zu setzen

    Ja, siehe seek (3. Parameter).

    Siechfred

    1. Hallo Siechfred,

      Ja, siehe seek (3. Parameter).

      Danke. Ich bin gerade erst nach Hause gekommen, hatte die Lösung
      allerdings gefunden. seek(FILE,0,2) war es.

      Nun, ich möchte gerne eine Datei ab einer bestimmten Zeile lesen.
      Um genau zu sein, die _letzten_ n Zeilen einer Datei. Die Datei
      wächst stetig um mehrere Zeilen an.

      Da jede Zeile in der Datei die gleiche Stringlänge hat, benötige ich
      die Größe der Datei in Bytes, um an die Richtige Stelle in der Datei
      mit seek springen zu können.

      Mein bisheriges Vorgehen:

      sysopen FILE,$file,O_RDONLY or die $!;
      flock(FILE,LOCK_SH);
      my index = [];
      my $i = 0;

      while (<FILE>) {
         $index->[$i] = tell(FILE);
         $i++;
      }

      seek(FILE,$index->[$i-30],0); # 30 = Anzahl Zeilen

      while (<FILE>) {
         # Verarbeitung
      }

      close FILE;

      Dieses Verfahren bringts nicht mehr, da die Dateien mittlerweile
      eine Größe von mehreren Gigabytes haben und der Durchlauf einfach
      zu lange dauert.

      Mein geplantes neues Vorgehen:

      my $lsize = 500; # Zeilenlänge in Bytes
      sysopen FILE,$file,O_RDONLY or die $!;
      flock(FILE,LOCK_SH);
      seek(FILE,0,2);
      my $bytes = tell(FILE);
      my $pos = $bytes-$lsize*30; # 30 = Anzahl Zeilen
      seek(FILE,$pos,0);

      while (<FILE>) {
         # Verarbeitung
      }

      close FILE;

      Ist das so richtig? Ich habe es noch nicht probiert und muss noch
      ein wenig basteln. An dieser Stelle habe ich aber noch eine andere
      Frage...

      Wie splitte ich am besten jede Zeile in ihre Einzelstrings?
      Mit substr oder unpack?

      Eine Zeile hat zum Beispiel den Aufbau:

      Spalte 1  Spalte 2  Spalte 3  Spalte 4  Spalte 5

      dies      ist       ein       test      nummer 1
      und       noch      ein       test      nummer 2
      schon     wieder    ein       test      nummer 3

      Mit split selber würde es nicht gehen, da jeder Delimiter in einer
      Spalte selber vorkommen könnte.

      Für Hilfe wäre ich super dankbar.

      Syntaxfehler mögen mir vergeben werden :-)

      Greez,
      opi

      --
      Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
      1. Ja, siehe seek (3. Parameter).

        Danke. Ich bin gerade erst nach Hause gekommen, hatte die Lösung
        allerdings gefunden. seek(FILE,0,2) war es.

        oder seek FILE, 0, SEEK_END

        da du sowieso schon Fnctl einbindest wäre das durchaus sinnvoll (da Plattform unabhängiger - wenn man's braucht)

        Nun, ich möchte gerne eine Datei ab einer bestimmten Zeile lesen.
        Um genau zu sein, die _letzten_ n Zeilen einer Datei. Die Datei
        wächst stetig um mehrere Zeilen an.

        Da gibt's ein Modul (komm grad nicht auf den Namen) das dürfte aber im Prinzip nichts anderes machen als dein geplantes vorgehen (ausserdem magst du ja keine Module, oder ;-) )

        Wie splitte ich am besten jede Zeile in ihre Einzelstrings?
        Mit substr oder unpack?

        Eine Zeile hat zum Beispiel den Aufbau:

        Spalte 1  Spalte 2  Spalte 3  Spalte 4  Spalte 5

        dies      ist       ein       test      nummer 1
        und       noch      ein       test      nummer 2
        schon     wieder    ein       test      nummer 3

        Mit split selber würde es nicht gehen, da jeder Delimiter in einer
        Spalte selber vorkommen könnte.

        bedeutet das das jede Spalte eine fixe Länge hat und keine Tabs drin sind?

        Dann würde ich substr verwenden.

        Struppi.

        1. Da gibt's ein Modul (komm grad nicht auf den Namen) das dürfte aber im Prinzip nichts anderes machen als dein geplantes vorgehen (ausserdem magst du ja keine Module, oder ;-) )

          gefunden: http://search.cpan.org/~uri/File-ReadBackwards-1.04/ReadBackwards.pm

          Struppi.

        2. Hallo Struppi,

          ich habe lange nichts mehr von dir gelesen :-)

          oder seek FILE, 0, SEEK_END

          das wußte ich noch nicht! Supi!

          Nun, ich möchte gerne eine Datei ab einer bestimmten Zeile lesen.
          Um genau zu sein, die _letzten_ n Zeilen einer Datei. Die Datei
          wächst stetig um mehrere Zeilen an.

          Da gibt's ein Modul (komm grad nicht auf den Namen) das dürfte aber im Prinzip nichts anderes machen als dein geplantes vorgehen (ausserdem magst du ja keine Module, oder ;-) )

          Na mittlerweile wächst mein Interesse an Modulen, da mein Perl immer
          besser wird und ich viele Abläufe besser verstehe :-)

          Allerdings versuche ich neues Gebiet immer zuerst ohne Modul
          anzupacken.

          Wie splitte ich am besten jede Zeile in ihre Einzelstrings?
          Mit substr oder unpack?

          Eine Zeile hat zum Beispiel den Aufbau:

          Spalte 1  Spalte 2  Spalte 3  Spalte 4  Spalte 5

          dies      ist       ein       test      nummer 1
          und       noch      ein       test      nummer 2
          schon     wieder    ein       test      nummer 3

          Mit split selber würde es nicht gehen, da jeder Delimiter in einer
          Spalte selber vorkommen könnte.

          bedeutet das das jede Spalte eine fixe Länge hat und keine Tabs drin sind?

          Ja genau. Die Datei fülle ich selber mit Daten und ich habe mir
          einfach erlaubt, für jede Spalte eine feste Länge zu definieren.
          Natürlich hätte ich auch die Daten einfach nebeneinander schreiben
          können mit einem Whitespace als Delimiter - in Dateien, bei denen
          ein Whitespace in einer Spalte selbst nicht vorkommen würde -,
          allerdings müsste ich dann weiterhin mein erstes Beispiel nutzen,
          dass leider ab einer bestimmten Größe der Datei sehr lahmt.

          Dann würde ich substr verwenden.

          Diese Antwort habe ich schon irgendwie erwartet. Ich habe heute
          mittag auf irgendeiner Seite gelesen, dass man für mehrere Felder
          unpack nutzen sollte. Aber gleichzeitig stand auch dabei, das unpack
          um einiges langsamer sein soll als substr. Wann würde es sich also
          lohnen, unpack statt substr einzusetzen? Wenn ich nur 5 Felder habe
          und 5 mal substr anwende... ok! Aber wie schaut es aus, wenn ich
          Beispielsweise 30 Felder zerteilen muss? Würde sich dann eher unpack
          lohnen?

          Was hälst du denn von meinem zweiten Beispiel? Gibt es eventuell
          eine bessere Lösung? Nur her damit :-)

          Greez,
          opi

          --
          Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
          1. oder seek FILE, 0, SEEK_END

            das wußte ich noch nicht! Supi!

            Im Zweifel gibt es auch eine Dokumentation zu den Modulen. Die von Fnctl ist kurz aber da wird zumindest drauf hingewiesen.

            Dann würde ich substr verwenden.

            Diese Antwort habe ich schon irgendwie erwartet. Ich habe heute
            mittag auf irgendeiner Seite gelesen, dass man für mehrere Felder
            unpack nutzen sollte. Aber gleichzeitig stand auch dabei, das unpack
            um einiges langsamer sein soll als substr. Wann würde es sich also
            lohnen, unpack statt substr einzusetzen? Wenn ich nur 5 Felder habe
            und 5 mal substr anwende... ok! Aber wie schaut es aus, wenn ich
            Beispielsweise 30 Felder zerteilen muss? Würde sich dann eher unpack
            lohnen?

            Was hälst du denn von meinem zweiten Beispiel? Gibt es eventuell
            eine bessere Lösung? Nur her damit :-)

            Ich benutze unpack eher selten, kann also dir leider da nicht weiterhelfen.

            Aber wenn du Wissen willst was schneller ist  dann solltest du dir mal das Benchmark Modul anschauen. Dann kannst du es selber rausfinden, damit hab ich auch schon ein paar Optimierungen gebaut. Wobei das nicht immer leicht ist, da natürlich bei Dateioperationen auch andere Faktoren eine Rolle spielen.

            Struppi.

            1. Hallo,

              Aber wenn du Wissen willst was schneller ist  dann solltest du dir mal das Benchmark Modul anschauen. Dann kannst du es selber rausfinden, damit hab ich auch schon ein paar Optimierungen gebaut. Wobei das nicht immer leicht ist, da natürlich bei Dateioperationen auch andere Faktoren eine Rolle spielen.

              Ok. Eine letzte Frage habe ich noch.

              Die Datei, die ich auslese, fülle ich mit dem folgendem Beispiel:

              Auf Aufteilung der Zeile durch Whitespaces sei mal so dahin
              geschrieben...

              foreach my $zeile (@$zeilen) {
                 my $spalten = [ split / /, $zeile ];
                 foreach my $spalte (@$spalten) {
                    print FILE "$_" . ' ' x 10-lenght($spalte);
                 }
                 print FILE "\n";
              }

              Auf diese Weise hat jede Spalte eine Länge von 10 Zeichen.

              Kann man das so machen oder ist das sehr umständlich?

              Greez,
              opi

              --
              Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
              1. Hallo,

                print FILE "$_" . ' ' x 10-lenght($spalte);

                print FILE "$spalte" . ' ' x 10-lenght($spalte);

                Sorry!

                Greez,
                opi

                --
                Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
              2. Tag opi.

                Auf diese Weise hat jede Spalte eine Länge von 10 Zeichen.
                Kann man das so machen oder ist das sehr umständlich?

                Schau dir mal printf/sprintf an.

                Siechfred

                1. Hallo Siechfred,

                  Schau dir mal printf/sprintf an.

                  my $string = "test";

                  print "1234567890\n"
                  printf '%10s', $string;
                  print "\n";

                  Ausgabe ...

                  1234567890
                  ______test

                  print "1234567890\n"
                  printf '%10s', $string;
                  print "\n";

                  Ausgabe ...

                  1234567890
                  test______

                  das ist genial und wird bestimmt um einiges schneller laufen als
                  print + lenght!

                  Supi! Danke!

                  Hast du schonmal mit Benchmarks rumgespielt?
                  Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der
                  Manpage?

                  Greez,
                  opi

                  --
                  Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                  1. Tag opi.

                    Hast du schonmal mit Benchmarks rumgespielt?

                    Nicht direkt, nur mit Time::HiRes.

                    Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der Manpage?

                    Hm, ich kenne nur Benchmark::Timer, habe es aber selber noch nicht benutzt.

                    Siechfred

                    1. Hallo Siechred,

                      ich hab mal ein wenig im Archiv rum gesucht und bin auf einen Thread
                      gestoßen, in dem Struppi mal einen Benchmark ausgeführt hat.

                      Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der Manpage?

                      Hm, ich kenne nur Benchmark::Timer, habe es aber selber noch nicht benutzt.

                      use Benchmark;

                      my $string = 'string\n';

                      Benchmark::cmpthese(-1, {
                              'print'   =>  sub {  print "$string" . ' ' x 10-length($string);  },
                              'printf'  =>  sub {  printf '%-10s', $string;  },
                      });

                      Rate  print printf
                      print  127242/s     --   -46%
                      printf 236566/s    86%     --

                      printf ist fast um das doppelte schneller. Mein klarer Favorit :-)

                      Greez,
                      opi

                      --
                      Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                      1. Hallo,

                        use Benchmark;

                        my $string = 'string\n';

                        Benchmark::cmpthese(-1, {
                                'print'   =>  sub {  print "$string" . ' ' x 10-length($string);  },
                                'printf'  =>  sub {  printf '%-10s', $string;  },
                        });

                        Rate  print printf
                        print  127242/s     --   -46%
                        printf 236566/s    86%     --

                        Sorry, da war ein Syntaxfehler drin:

                        print "$string" . ' ' x (10-length($string));

                        Die Ausgabe schaut dann etwas anders aus:

                        Rate  print printf
                        print  196608/s     --   -24%
                        printf 259646/s    32%     --

                        Aber printf ist noch immer schneller.

                        Greez,
                        opi

                        --
                        Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                  2. Hast du schonmal mit Benchmarks rumgespielt?
                    Ich würde das gerne mal testen. Kennst du eine gute Doku ausser der
                    Manpage?

                    Eigentlich reicht die.

                    Hier mal der vergleich mit DB_File vs. Indexdatei

                    Wobei ich den code ein bisschen geändert habe, da so die Index datei immer neu eingelesen wird.

                    Das Ergebniss bei mir mit 10,000 aufrufen:

                    Benchmark: timing 10000 iterations of DB_File, idx File...
                       DB_File:  3 wallclock secs ( 2.36 usr +  0.00 sys =  2.36 CPU) @ 4237.29/s (n
                    =10000)
                      idx File:  6 wallclock secs ( 5.55 usr +  0.00 sys =  5.55 CPU) @ 1801.80/s (n
                    =10000)
                               Rate idx File  DB_File
                    idx File 1802/s       --     -57%
                    DB_File  4237/s     135%       --

                    DB_File ist viel schneller

                      
                    #!/usr/perl/bin -w  
                      
                    use strict;  
                      
                    package idx_datei;  
                      
                    # usage: build_index(*DATA_HANDLE, *INDEX_HANDLE)  
                    sub build_index  
                    {  
                        my $data_file  = shift;  
                        my $index_file = shift;  
                        my $offset     = 0;  
                        while (<$data_file>)  
                        {  
                             print $index_file pack("N", $offset);  
                             $offset = tell($data_file);  
                        }  
                    }  
                    # usage: line_with_index(*DATA_HANDLE, *INDEX_HANDLE, $LINE_NUMBER)  
                    # returns line or undef if LINE_NUMBER was out of range  
                    my $entry;  
                    sub line_with_index  
                    {  
                        my $data_file   = shift;  
                        my $index_file  = shift;  
                        my $line_number = shift;  
                        unless($entry)  
                        {  
                        my $size = length(pack("N", 0));  
                        my $i_offset = $size * ($line_number-1);  
                        seek($index_file, $i_offset, 0) or return;  
                        read($index_file, $entry, $size);  
                        }  
                        my $d_offset = unpack("N", $entry);  
                        seek($data_file, $d_offset, 0);  
                        return scalar(<$data_file>);  
                    }  
                      
                    package main;  
                      
                    use Benchmark;  
                      
                    my $lines = 100;  
                    # idx File  
                    my $file = 'file_idx.txt';  
                    createfile();  
                    open(FILE, "< $file") or die "Can't open $file for reading: $!\n";  
                    open(INDEX, "+> $file.idx")  
                            or die "Can't open $file.idx for read/write: $!\n";  
                    idx_datei::build_index(*FILE, *INDEX);  
                      
                    # DB_File  
                      
                    use DB_File;  
                    use Fcntl;  
                    my $db_file = 'file_db.db';  
                    my @lines;  
                    my $tie = tie(@lines, "DB_File", $db_file, O_RDWR | O_CREAT, 0666, $DB_RECNO)  
                       or die "Cannot open file $db_file: $!\n";  
                    create_db_file();  
                      
                      
                    # Vergleich  
                    my $line;  
                    Benchmark::cmpthese( 10000, {  
                    'idx File' => sub { $line = idx_datei::line_with_index(*FILE, *INDEX, int(rand() * $lines )); },  
                    'DB_File' => sub { $line = $lines[int(rand() * $lines)]; }  
                    });  
                      
                      
                    sub createfile  
                    {  
                        open(FILE, ">$file");  
                        print FILE "$_.". ( 'x' x (rand()*80) ). "\n" for(0...$lines);  
                        close FILE;  
                    }  
                      
                    sub create_db_file  
                    {  
                    $lines[$_] =  "$_.". ( 'x' x (rand()*80) ). "\n" for(0...$lines);  
                    }  
                    
                    

                    Struppi.

                    1. Tag Struppi.

                      Hier mal der vergleich mit DB_File vs. Indexdatei [...] DB_File ist viel schneller

                      Ja, so steht es auch auf der von mir verlinkten Seite.

                      Siechfred

      2. Tag opi.

        Da jede Zeile in der Datei die gleiche Stringlänge hat, benötige ich
        die Größe der Datei in Bytes, um an die Richtige Stelle in der Datei
        mit seek springen zu können.

        Du könntest dir auch eine Indexdatei anlegen, mit deren Hilfe es problemlos möglich wäre, an eine bestimmte Stelle der Textdatei zu springen.

        Wie splitte ich am besten jede Zeile in ihre Einzelstrings? Mit substr oder unpack?

        Vielleicht funktioniert ja auch split mit einem entsprechenden Suchmuster.

        Siechfred

        1. Hallo Siechfred,

          Tag opi.

          Da jede Zeile in der Datei die gleiche Stringlänge hat, benötige ich
          die Größe der Datei in Bytes, um an die Richtige Stelle in der Datei
          mit seek springen zu können.

          Du könntest dir auch eine Indexdatei anlegen, mit deren Hilfe es problemlos möglich wäre, an eine bestimmte Stelle der Textdatei zu springen.

          Meinst du eine zusätzliche Datei die bei jedem Append gepflegt wird?

          Zum Beispiel:

          datei.txt
          datei_index.txt

          In datei_index.txt steht dann immer der aktuelle Byte-Wert der
          Position, zu ich gerne springen möchte? Das wäre eine Überlegung
          wert. Diesen Wert könnte ich auch in der ersten Zeile von datei.txt
          ablegen mit einer festen Länge, zum Beispiel

          zeile30=000000030043

          Oder meinst du in der datei.txt vor jeder Zeile einen Wert abzulegen?

          Hierfür müsste ich trotzallem die Datei bis zu der Position durchlesen
          und den Index auswerten, was mir zu lange dauert.

          Greez,
          opi

          --
          Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
          1. Tag opi.

            Du könntest dir auch eine Indexdatei anlegen, mit deren Hilfe es problemlos möglich wäre, an eine bestimmte Stelle der Textdatei zu springen.
            Meinst du eine zusätzliche Datei die bei jedem Append gepflegt wird?

            So in etwa. Eine ziemlich schnelle Lösung mit Index-Datei findest du hier:
            http://www.unix.org.ua/orelly/perl/cookbook/ch08_09.htm

            Das Einzige, das etwas dauert, ist das erstmalige Generieren der Index-Datei. Dann aber flutscht das Programm so richtig :-)

            Siechfred

      3. Hello again,

        Spalte 1  Spalte 2  Spalte 3  Spalte 4  Spalte 5

        dies      ist       ein       test      nummer 1
        und       noch      ein       test      nummer 2
        schon     wieder    ein       test      nummer 3

        Mit split selber würde es nicht gehen, da jeder Delimiter in einer
        Spalte selber vorkommen könnte.

        ich war nochmal so frei und habe getestet, ob sich eine Datei, in der
        die Daten in Tabellenform mit fester Stringlänge abgelegt werden
        auch wirklich lohnt oder ob ich einen beliebigen Delimiter als
        Trennzeichen nutze und die Daten einfach mit split oder etwas
        anderem aufteile.

        Mein Resultat ist, dass substr in jedem Fall schneller ist und das
        sich eine Datendatei in Tabellenform mit fester Stringlänge in jedem
        Fall lohnt.

        Ob so:

        my $string = "string0    string1   string2   string3   string4   string5   string6   string7   string8   string9   ";

        Benchmark::cmpthese(-1, {
                   'substr'  =>  sub { my $f0 = substr($string, 0, 10);
                                       my $f1 = substr($string, 11, 10);
                                       my $f2 = substr($string, 21, 10);
                                       my $f3 = substr($string, 31, 10);
                                       my $f4 = substr($string, 41, 10);
                                       my $f5 = substr($string, 51, 10);
                                       my $f6 = substr($string, 61, 10);
                                       my $f7 = substr($string, 71, 10);
                                       my $f8 = substr($string, 81, 10);
                                       my $f9 = substr($string, 91, 10);
                                     },
                   'split'   =>  sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string; },
                   'regexp'  =>  sub { $string =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
                                       my $f0 = $1;
                                       my $f1 = $2;
                                       my $f2 = $3;
                                       my $f3 = $4;
                                       my $f4 = $5;
                                       my $f5 = $6;
                                       my $f6 = $7;
                                       my $f7 = $8;
                                       my $f8 = $9;
                                       my $f9 = $10;
                                 },
           });

        Benchmark: running regexp, split, substr for at least 1 CPU seconds...
            regexp:  1 wallclock secs ( 1.00 usr +  0.06 sys =  1.06 CPU) @ 40572.64/s (n=43007)
             split:  1 wallclock secs ( 1.02 usr +  0.03 sys =  1.05 CPU) @ 51199.05/s (n=53759)
            substr:  1 wallclock secs ( 1.04 usr +  0.04 sys =  1.08 CPU) @ 99554.63/s (n=107519)
                  Rate regexp  split substr
        regexp 40573/s     --   -21%   -59%
        split  51199/s    26%     --   -49%
        substr 99555/s   145%    94%     --

        Oder so:

        my $string1 = "string0    string1   string2   string3   string4   string5   string6   string7   string8   string9   ";
           my $string2 = "string0 string1 string2 string3 string4 string5 string6 string7 string8 string9";

        Benchmark::cmpthese(-1, {
                   'substr'  =>  sub { my $f0 = substr($string1, 0, 10);
                                       my $f1 = substr($string1, 11, 10);
                                       my $f2 = substr($string1, 21, 10);
                                       my $f3 = substr($string1, 31, 10);
                                       my $f4 = substr($string1, 41, 10);
                                       my $f5 = substr($string1, 51, 10);
                                       my $f6 = substr($string1, 61, 10);
                                       my $f7 = substr($string1, 71, 10);
                                       my $f8 = substr($string1, 81, 10);
                                       my $f9 = substr($string1, 91, 10);
                                     },
                   'split'   =>  sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string2; },
                   'regexp'  =>  sub { $string2 =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
                                       my $f0 = $1;
                                       my $f1 = $2;
                                       my $f2 = $3;
                                       my $f3 = $4;
                                       my $f4 = $5;
                                       my $f5 = $6;
                                       my $f6 = $7;
                                       my $f7 = $8;
                                       my $f8 = $9;
                                       my $f9 = $10;
                                 },
           });
        }

        Benchmark: running regexp, split, substr for at least 1 CPU seconds...
            regexp:  2 wallclock secs ( 1.22 usr +  0.03 sys =  1.25 CPU) @ 21504.00/s (n=26880)
             split:  1 wallclock secs ( 1.03 usr +  0.02 sys =  1.05 CPU) @ 54613.33/s (n=57344)
            substr:  2 wallclock secs ( 1.03 usr +  0.06 sys =  1.09 CPU) @ 98642.20/s (n=107520)
                  Rate regexp  split substr
        regexp 21504/s     --   -61%   -78%
        split  54613/s   154%     --   -45%
        substr 98642/s   359%    81%     --

        Greez,
        opi

        --
        Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
        1. Hallo,

          oh je, ich nehme alles wieder zurück!

          Ich habe ganz vergessen, dass nach dem substr ja auch noch die
          Leerzeichen weggeschnitten werden müssen, die am Ende des Strings
          vorkommen könnten.

          Somit ist mein Beispiel hinfällig!

          my $string = "string0    string1   string2   string3   string4   string5   string6   string7   string8   string9   ";

          Benchmark::cmpthese(-1, {
                     'substr'  =>  sub { my $f0 = substr($string, 0, 10);
                                         my $f1 = substr($string, 11, 10);
                                         my $f2 = substr($string, 21, 10);
                                         my $f3 = substr($string, 31, 10);
                                         my $f4 = substr($string, 41, 10);
                                         my $f5 = substr($string, 51, 10);
                                         my $f6 = substr($string, 61, 10);
                                         my $f7 = substr($string, 71, 10);
                                         my $f8 = substr($string, 81, 10);
                                         my $f9 = substr($string, 91, 10);
                                       },
                     'split'   =>  sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string; },
                     'regexp'  =>  sub { $string =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
                                         my $f0 = $1;
                                         my $f1 = $2;
                                         my $f2 = $3;
                                         my $f3 = $4;
                                         my $f4 = $5;
                                         my $f5 = $6;
                                         my $f6 = $7;
                                         my $f7 = $8;
                                         my $f8 = $9;
                                         my $f9 = $10;
                                   },
             });

          Benchmark: running regexp, split, substr for at least 1 CPU seconds...
              regexp:  1 wallclock secs ( 1.00 usr +  0.06 sys =  1.06 CPU) @ 40572.64/s (n=43007)
               split:  1 wallclock secs ( 1.02 usr +  0.03 sys =  1.05 CPU) @ 51199.05/s (n=53759)
              substr:  1 wallclock secs ( 1.04 usr +  0.04 sys =  1.08 CPU) @ 99554.63/s (n=107519)
                    Rate regexp  split substr
          regexp 40573/s     --   -21%   -59%
          split  51199/s    26%     --   -49%
          substr 99555/s   145%    94%     --

          Nun habe ich es mal das Wegschneiden der Whitespaces hinzugenommen:

          my $string = "string0    string1   string2   string3   string4   string5   string6   string7   string8   string9   ";

          Benchmark::cmpthese(-1, {
                     'substr'  =>  sub { (my $f0 = substr($string,  0, 10)) =~ s/\s+$//;
                                         (my $f1 = substr($string, 11, 10)) =~ s/\s+$//;
                                         (my $f2 = substr($string, 21, 10)) =~ s/\s+$//;
                                         (my $f3 = substr($string, 31, 10)) =~ s/\s+$//;
                                         (my $f4 = substr($string, 41, 10)) =~ s/\s+$//;
                                         (my $f5 = substr($string, 51, 10)) =~ s/\s+$//;
                                         (my $f6 = substr($string, 61, 10)) =~ s/\s+$//;
                                         (my $f7 = substr($string, 71, 10)) =~ s/\s+$//;
                                         (my $f8 = substr($string, 81, 10)) =~ s/\s+$//;
                                         (my $f9 = substr($string, 91, 10)) =~ s/\s+$//;
                                       },
                     'split'   =>  sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = split /\s+/, $string; },
                     'regexp'  =>  sub { $string =~ /^(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+$/;
                                         my $f0 = $1;
                                         my $f1 = $2;
                                         my $f2 = $3;
                                         my $f3 = $4;
                                         my $f4 = $5;
                                         my $f5 = $6;
                                         my $f6 = $7;
                                         my $f7 = $8;
                                         my $f8 = $9;
                                         my $f9 = $10;
                                   },
             });

          Benchmark: running regexp, split, substr for at least 1 CPU seconds...
              regexp:  2 wallclock secs ( 0.93 usr +  0.07 sys =  1.00 CPU) @ 40325.00/s (n=40325)
               split:  1 wallclock secs ( 0.97 usr +  0.06 sys =  1.03 CPU) @ 45983.50/s (n=47363)
              substr:  1 wallclock secs ( 1.07 usr +  0.02 sys =  1.09 CPU) @ 41533.03/s (n=45271)
                    Rate regexp substr  split
          regexp 40325/s     --    -3%   -12%
          substr 41533/s     3%     --   -10%
          split  45983/s    14%    11%     --

          und siehe da... die substr Variante wird natürlich langsamer.

          Kann ich da noch etwas Tunen? Eventuell einen Ersatz für das
          Schneiden mittels s/\s+$// ???

          Greez,
          opi

          --
          Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
          1. Tag opi.

            Kann ich da noch etwas Tunen?

            Ja, einen RegExp im Listenkontext, der liefert mir hier das beste Ergebnis:

            Benchmark::cmpthese(-1, {  
                'substr'  =>  sub { (my $f0 = substr($string,  0, 10)) =~ s/\s+$//;  
                                           (my $f1 = substr($string, 11, 10)) =~ s/\s+$//;  
                                           (my $f2 = substr($string, 21, 10)) =~ s/\s+$//;  
                                           (my $f3 = substr($string, 31, 10)) =~ s/\s+$//;  
                                           (my $f4 = substr($string, 41, 10)) =~ s/\s+$//;  
                                           (my $f5 = substr($string, 51, 10)) =~ s/\s+$//;  
                                           (my $f6 = substr($string, 61, 10)) =~ s/\s+$//;  
                                           (my $f7 = substr($string, 71, 10)) =~ s/\s+$//;  
                                           (my $f8 = substr($string, 81, 10)) =~ s/\s+$//;  
                                           (my $f9 = substr($string, 91, 10)) =~ s/\s+$//;  
                                         },  
                'split'   =>  sub { my @fn = split /\s+/, $string; },  
                'regexp'  =>  sub { my @fn = $string =~ /(\w+?\d)/g; },  
            });
            

            Ergibt:

            Rate regexp substr  split
            regexp 24325/s     --   -51%   -52%
            substr 49320/s   103%     --    -2%
            split  50242/s   107%     2%     --

            Siechfred

            1. Hallo,

              Tag opi.

              Kann ich da noch etwas Tunen?

              Ja, einen RegExp im Listenkontext, der liefert mir hier das beste Ergebnis:

              Benchmark::cmpthese(-1, {

              'substr'  =>  sub { (my $f0 = substr($string,  0, 10)) =~ s/\s+$//;
                                             (my $f1 = substr($string, 11, 10)) =~ s/\s+$//;
                                             (my $f2 = substr($string, 21, 10)) =~ s/\s+$//;
                                             (my $f3 = substr($string, 31, 10)) =~ s/\s+$//;
                                             (my $f4 = substr($string, 41, 10)) =~ s/\s+$//;
                                             (my $f5 = substr($string, 51, 10)) =~ s/\s+$//;
                                             (my $f6 = substr($string, 61, 10)) =~ s/\s+$//;
                                             (my $f7 = substr($string, 71, 10)) =~ s/\s+$//;
                                             (my $f8 = substr($string, 81, 10)) =~ s/\s+$//;
                                             (my $f9 = substr($string, 91, 10)) =~ s/\s+$//;
                                           },
                  'split'   =>  sub { my @fn = split /\s+/, $string; },
                  'regexp'  =>  sub { my @fn = $string =~ /(\w+?\d)/g; },
              });

              
              >   
              > Ergibt:  
              >   
              >           Rate regexp substr  split  
              > regexp 24325/s     --   -51%   -52%  
              > substr 49320/s   103%     --    -2%  
              > split  50242/s   107%     2%     --  
                
              wie kommst du darauf, dass regexp mit 24325 Iterations pro Sekunde  
              das beste Ergebnis liefert? Für mich ist split noch am schnellsten  
              mit 50242 Iterations pro (CPU-) Sekunde.  
                
              Oder irre ich mich an dieser Stelle etwa?  
                
              Greez,  
              opi
              
              -- 
              Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|  
              
              
              1. Tag opi.

                wie kommst du darauf, dass regexp mit 24325 Iterations pro Sekunde
                das beste Ergebnis liefert? Für mich ist split noch am schnellsten
                mit 50242 Iterations pro (CPU-) Sekunde.

                Nee, du hast schon Recht ... war wohl ein bisschen zu viel heute :-)

                Siechfred

                1. Hallo,

                  wie kommst du darauf, dass regexp mit 24325 Iterations pro Sekunde
                  das beste Ergebnis liefert? Für mich ist split noch am schnellsten
                  mit 50242 Iterations pro (CPU-) Sekunde.

                  Nee, du hast schon Recht ... war wohl ein bisschen zu viel heute :-)

                  für mich war das auch mal wieder ein langer Tag, aber zum Glück ist
                  morgen Freitag - obwohl ich auch nicht besonders viel vom WE haben
                  werde.

                  Um nochmal auf meine Frage zu kommen... hast du etwas "schnelleres"
                  als s/\s+$// parat bezüglich der Zerteilung eines Strings mit substr,
                  damit ich split toppen kann?

                  Ich müsste mir printf und sprintf nochmal anschauen, denn wenn die
                  Ausgabe einer festen Stringlänge mittels printf '%-10s' funktioniert,
                  dann gibt es doch auch bestimmt etwas in die andere Richtung, um den
                  String ohne Leerzeichen zu filtern. Ich muss mal stöbern...

                  Gutes nächtle ansonsten... vielleicht schau ich später nochmal rein!

                  Greez,
                  opi

                  --
                  Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                  1. Hallo Siechfred,

                    dann gibt es doch auch bestimmt etwas in die andere Richtung, um den
                    String ohne Leerzeichen zu filtern. Ich muss mal stöbern...

                    nun ich habe nichts anderes gefunden, als mit regexp die
                    Leerzeichen zu entfernen.

                    Meine endgültigen Lösungen sind also:

                    my $string = "string 0  string 1  string 2  string 3  string 4  string 5  string 6  string 7  string 8  string 9  ";  
                      
                    Benchmark::cmpthese(-1, {  
                               'substr'  =>  sub { (my $f0 = substr($string,  0, 10)) =~ s/\s+$//;  
                                                   (my $f1 = substr($string, 11, 10)) =~ s/\s+$//;  
                                                   (my $f2 = substr($string, 21, 10)) =~ s/\s+$//;  
                                                   (my $f3 = substr($string, 31, 10)) =~ s/\s+$//;  
                                                   (my $f4 = substr($string, 41, 10)) =~ s/\s+$//;  
                                                   (my $f5 = substr($string, 51, 10)) =~ s/\s+$//;  
                                                   (my $f6 = substr($string, 61, 10)) =~ s/\s+$//;  
                                                   (my $f7 = substr($string, 71, 10)) =~ s/\s+$//;  
                                                   (my $f8 = substr($string, 81, 10)) =~ s/\s+$//;  
                                                   (my $f9 = substr($string, 91, 10)) =~ s/\s+$//;  
                                                 },  
                               'unpack1' =>  sub { my $field = [ map /^(.+?)\s+$/, unpack ("a10a10a10a10a10a10a10a10a10a10",$string) ]; },  
                               'unpack2' =>  sub { my ($f0, $f1, $f2, $f3, $f4, $f5, $f6, $f7, $f8, $f9) = unpack ("a10a10a10a10a10a10a10a10a10a10",$string);  
                                                   $f0 =~ s/\s+$//;  
                                                   $f1 =~ s/\s+$//;  
                                                   $f2 =~ s/\s+$//;  
                                                   $f3 =~ s/\s+$//;  
                                                   $f4 =~ s/\s+$//;  
                                                   $f5 =~ s/\s+$//;  
                                                   $f6 =~ s/\s+$//;  
                                                   $f7 =~ s/\s+$//;  
                                                   $f8 =~ s/\s+$//;  
                                                   $f9 =~ s/\s+$//;  
                                                 },  
                               'split'   =>  sub { my $field = [ map /^(.+?)\s+$/, split /(.{10})/, $string ]; },  
                               'regexp1' =>  sub { my $field = [ map /^(.+?)\s+$/, $string =~ /(.{10})/g ]; },  
                               'regexp2' =>  sub { my $field = [ map /^(.+?)\s+$/, $string =~ /(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})(.{10})/ ]; }  
                    });
                    

                    Rate  split2 regexp2 regexp1 unpack1 unpack2  substr
                    split   25373/s      --    -12%    -16%    -21%    -66%    -71%
                    regexp2 28709/s     13%      --     -5%    -11%    -61%    -67%
                    regexp1 30351/s     20%      6%      --     -6%    -59%    -65%
                    unpack1 32288/s     27%     12%      6%      --    -57%    -62%
                    unpack2 74472/s    194%    159%    145%    131%      --    -14%
                    substr  86102/s    239%    200%    184%    167%     16%      --

                    split und regexp1 fallen weg, falls Spalten unterschiedliche
                    Längen haben sollten.

                    substr wäre die schnellste Variante.

                    Greez,
                    opi

                    --
                    Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|
                    1. Rate  split2 regexp2 regexp1 unpack1 unpack2  substr
                      split   25373/s      --    -12%    -16%    -21%    -66%    -71%
                      regexp2 28709/s     13%      --     -5%    -11%    -61%    -67%
                      regexp1 30351/s     20%      6%      --     -6%    -59%    -65%
                      unpack1 32288/s     27%     12%      6%      --    -57%    -62%
                      unpack2 74472/s    194%    159%    145%    131%      --    -14%
                      substr  86102/s    239%    200%    184%    167%     16%      --

                      Hehe, macht Spaß mit Benchmark rumzuspielen gerade wenn man kleinere Routinen optimieren möchte.

                      Struppi.

                      1. Hallo,

                        Hehe, macht Spaß mit Benchmark rumzuspielen gerade wenn man kleinere Routinen optimieren möchte.

                        ja, es macht echt Spaß. Seit zwei Tagen mache ich nichts
                        anderes, als meine Skripts zu Tunen, dies und jenes aus-
                        zuprobieren. Es ist erstaunlich, wo man alles etwas rausholen
                        kann :-)

                        Greez,
                        opi

                        --
                        Selfcode: ie:( fl:( br:^ va:) ls:] fo:) rl:( n4:? ss:| de:] ch:? mo:|