Thread Sysopen in Kombination mit seek/sysseek und print (12 answers)
Opened by Gast at 2007-06-25 11:09

bloonix
 2007-06-26 14:47
#77797 #77797
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
Hallo Ralph,

also, entweder du benutzt sysread(), syswrite() und sysseek() oder aber
read(), print(), tell(), seek(). Beides zu vermischen ist keine gute Idee, so
steht es auch in der Dokumentation!

Quote
sysseek() bypasses normal buffered IO, so mixing this with reads (other than sysread, for example <> or read()) print, write, seek, tell, or eof may cause confusion.

Warum? Schau her...

Erst mal ein wenig Code zum Testen:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
use strict;
use warnings;
use Fcntl qw/ SEEK_CUR O_RDONLY LOCK_EX /;

sub sys_verwenden {
  print '-' x 30, "\n";

  sysopen my $fh, "file.txt", O_RDONLY or die $!;
  flock $fh, LOCK_EX or die $!;

  sysread($fh, my $buf, 50);
  my $pos = sysseek($fh, 0, SEEK_CUR);
  print "Position: $pos\n";
  print "Buffer:\n";
  print $buf, "\n";
  close $fh;
}

sub vermischt {
  print '-' x 30, "\n";

  sysopen my $fh, "file.txt", O_RDONLY or die $!;
  flock $fh, LOCK_EX or die $!;

  while (my $line = <$fh>) {
     printf "%5s %s", sysseek($fh, 0, SEEK_CUR), $line;
  }  

  close $fh;
}

sub ohne_sys {
  print '-' x 30, "\n";

  sysopen my $fh, "file.txt", O_RDONLY or die $!;
  flock $fh, LOCK_EX or die $!;

  while (my $line = <$fh>) {
     printf "%5s %s", tell($fh), $line;
  }  

  close $fh;
}

sys_verwenden();
vermischt();
ohne_sys();


Ausgabe von sys_verwenden()

Position: 50
Buffer:
AAAAAAAAAAAAAAAAAAAAAA
BBBBBBBBBBBBBBBBBBBBBB
CCCC


Wie du hier sehen kannst, macht sysread() und sysseek() genau das, was
es machen soll. sysread() liest 50 Bytes ein und sysseek() zeigt an, wo
man sich gerade befindet. Korrekt also! Weiter im Geschehen...

Ausgabe von vermischt()

 138 AAAAAAAAAAAAAAAAAAAAAA
 138 BBBBBBBBBBBBBBBBBBBBBB
 138 CCCCCCCCCCCCCCCCCCCCCC
 138 DDDDDDDDDDDDDDDDDDDDDD
 138 EEEEEEEEEEEEEEEEEEEEEE
 138 FFFFFFFFFFFFFFFFFFFFFF


Genau! WTF! Die Byteposition ist immer das Ende der Datei, die genau
138 Bytes groß ist. Also macht es überhaupt keinen Sinn <$fh> und
sysseek() zu vermischen. Soweit ich weiß, verwendet Perl readline(), wenn
<$fh> benutzt wird. Dann wird für gewöhnlich eine Zeile eingelesen, wenn
$/ nicht manipuliert wurde! Weiter...

Ausgabe von ohne_sys()

  23 AAAAAAAAAAAAAAAAAAAAAA
  46 BBBBBBBBBBBBBBBBBBBBBB
  69 CCCCCCCCCCCCCCCCCCCCCC
  92 DDDDDDDDDDDDDDDDDDDDDD
 115 EEEEEEEEEEEEEEEEEEEEEE
 138 FFFFFFFFFFFFFFFFFFFFFF


Das schaut doch schon besser aus! Hier wird genau die Mischung benutzt
die du brauchst: readline() + tell() + seek().

So, weiter zu deinem Skript, was ich ein wenig angepasst habe:

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use strict;
use warnings;
use Fcntl qw(:DEFAULT :flock SEEK_SET SEEK_CUR);
use utf8;

sysopen my $fh, "datei.txt", O_RDWR or die "Kann Datei nicht &ouml;ffnen: $!\n";
flock $fh, LOCK_EX or die "Kann Datei nicht sperren: $!\n";
binmode $fh, ':utf8';

my $pos = 0;

while (my $line = <$fh>) {
   chomp($line);
   my ($feld1, $feld2, $feld3) = split /\xA1/, $line;
   if ($feld1 eq "EEEEE") {
       seek($fh, $pos, SEEK_SET);
       print $fh "E-E-E¡$feld2¡$feld3\n";
   };  
   $pos = tell($fh);
}

close $fh;


Ausgabe:

AAAAAAA¡aaaaaaa¡aaa
BBBB¡bbbb¡bbb
CCCCCC¡cccc¡ccc
DDDDDDDD¡ddddd¡dddd
E-E-E¡eeeeeeeeee¡eee
FFFF¡fffff¡ff
GGGGGG¡ggggggggggggg¡ggg
HHHHH¡hhhhh¡h


Das ist doch genau das was du wolltest?

Hier noch ein paar Erläuterungen:

use utf8; und binmode $fh, ':utf8';
Wenn du in deinem Perlskript utf8 Zeichen verwendest, dann musst du
das Perl auch mitteilen, ansonsten wird sowas hier geschrieben:
E-E-E¡eeeeeeeeee¡eee

Gleiches gilt für das Filehandle. Du möchtest ja nicht nur lesen, sondern
auch schreiben. Also teile doch auch hier Perl mit, dass du utf8 lesen und
schreiben möchtest. Ohne utf8 steht bei mir immer in $feld1 folgendes:
EEEEE&� und somit kann "EEEEE" nicht matchen!

Gruss,
opi\n\n

<!--EDIT|opi|1182855038-->
What is a good module? That's hard to say.
What is good code? That's also hard to say.
One man's Thing of Beauty is another's man's Evil Hack.

View full thread Sysopen in Kombination mit seek/sysseek und print