Schrift
[thread]9118[/thread]

Sysopen in Kombination mit seek/sysseek und print



<< |< 1 2 >| >> 13 Einträge, 2 Seiten
Gast Gast
 2007-06-25 11:09
#77791 #77791
Irgendwie scheints unvorhersehbare Ergebnisse zu geben wenn
ich mit sysopen eine Datei öffne, und dann mit sysseek (oder
seek) zu bestimmten Stellen innerhalb der Datei springe, um
dort etwas mittels print hineinzuschreiben.

http://perldoc.perl.org/functions/sysseek.html
meint es könnte am Buffering (sysseek: nein <-> print: ja)
liegen.

Aber an einer benachbarten Doku-stelle findet sich aber
http://perldoc.perl.org/perlfaq....counter
Dort wird zwar nur an den Dateianfang gesprungen und nicht
mitten in die Datei, aber trotzdem wiederspricht diese
Fundstelle doch der ersteren was die Kombination von sysopen
und seek angeht?

Wer hat schonmal eine ähnliche Erfahrung mit sysopen, sysseek
und print gemacht?

Ich habs nun erstmal so gelöst daß ich die geänderte
Datei als ganzes neu schreiben lasse.  :-|

LG, Ralph

betterworld: Links verlinkt\n\n

<!--EDIT|betterworld|1182796150-->
pq
 2007-06-25 11:32
#77792 #77792
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
vielleicht zeigst du mal ein klein wenig code und beschreibst, was du mit
unvorhersehbaren ereignissen meinst?
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
RalphFFM
 2007-06-25 20:19
#77793 #77793
User since
2006-11-16
258 Artikel
BenutzerIn
[Homepage] [default_avatar]
Also, jetzt bin ich wieder zuhause.
Gegeben sei eine kleine Textdatei datei.txt mit folgendem Inhalt:
Code: (dl )
1
2
3
4
5
6
7
8
AAAAAAA¡aaaaaaa¡aaa
BBBB¡bbbb¡bbb
CCCCCC¡cccc¡ccc
DDDDDDDD¡ddddd¡dddd
EEEEE¡eeeeeeeeee¡eee
FFFFFFFF¡fffff¡ff
GGGGGG¡ggggggggggggg¡ggg
HHHHH¡hhhhh¡h


und mit folgendem kleinen Skriptteil hatte ich vor die Zeile
mit den vielen EEE..s zu ändern:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/perl
use warnings; use strict; use diagnostics;
use Fcntl qw(:DEFAULT :flock SEEK_SET SEEK_CUR);
sub systell { sysseek($_[0], 0, SEEK_CUR) }

sysopen FH, "datei.txt", O_RDWR or die "Kann Datei nicht &ouml;ffnen: $!\n";
flock FH, LOCK_EX or die "Kann Datei nicht sperren: $!\n";
my $pos = 0;
my ($feld1, $feld2, $feld3) = "";
while (<FH>) {
chomp;
($feld1, $feld2, $feld3) = split /\xA1/;
if ($feld1 eq "EEEEE") {
sysseek FH, $pos, SEEK_SET; # möchte aktuelle Zeile überschreiben
print FH "E-E-E¡eeeeeeeeee¡eee\n"; # geänderte Zeile
};
$pos = main::systell FH; # ich möchte den Zeilenanfang treffen
}
close FH;


Wieso schreibt mir das Skript die geänderte Zeile an die falsche Stelle?
Wo liegt der Fehler? Danke für jeden Tip. LG, Ralph
sid burn
 2007-06-25 21:59
#77794 #77794
User since
2006-03-29
1520 Artikel
BenutzerIn

user image
Benutz mal "seek" anstatt "sysseek" in deinem Bereits oben gepostet perldoc steht ja bereits drin das man "sysseek" nicht mit "print", <> etc. mischen sollte...

perldoc.perl.org/functions/sysseek.html
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.


Hab mir jetzt aber nicht angeschaut was dein Code macht...
Nicht mehr aktiv. Bei Kontakt: ICQ: 404181669 E-Mail: perl@david-raab.de
RalphFFM
 2007-06-26 00:42
#77795 #77795
User since
2006-11-16
258 Artikel
BenutzerIn
[Homepage] [default_avatar]
Seek anstatt sysseek hat leider keinen Unterschied bewirkt. :-(
Ronnie
 2007-06-26 01:08
#77796 #77796
User since
2003-08-14
2022 Artikel
BenutzerIn
[default_avatar]
Wie wäre es mit syswrite statt print?
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.
bloonix
 2007-06-26 15:04
#77798 #77798
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
Okay... ein wenig Nachforschung bringt die Antwort...

file.txt hat eine Größe von ca. 91080 Bytes

Code: (dl )
1
2
3
4
5
6
7
8
9
sub sys_seek {
  sysopen my $fh, "file.txt", O_RDONLY or die $!;
  flock $fh, LOCK_EX or die $!;
  print "Position: ", sysseek($fh, 0, SEEK_CUR), "\n";
  <$fh>;
  print "Position: ", sysseek($fh, 0, SEEK_CUR), "\n";
}

foo();


Position: 0 but true
Position: 4096


Jetzt ist auch klar, warum sysseek() etwas anderes zurückgibt! readline()
scheint immer 4096 Bytes zu buffern. sysseek() gibt also die Position
zurück, bis zu der gebuffert wurde, also bis wohin genau die Datei schon
eingelesen wurde. tell() gibt die aktuelle Position von readline() zurück,
was für gewöhlich das aktuelle Zeilenende ist. Davon weiß allerdings
sysseek() wenig. Deshalb ist die Vermischung von Beidem nicht so
prickelnd.

viele edits... sorry\n\n

<!--EDIT|opi|1182857837-->
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.
RalphFFM
 2007-06-26 15:07
#77799 #77799
User since
2006-11-16
258 Artikel
BenutzerIn
[Homepage] [default_avatar]
Hallo opi, vielen Dank, ich muß mir das Geschriebene heute abend zuhause
noch etwas auf der Zunge zergehen lassen, und ausprobieren.

Auf den Gedanken daß utf8 hier ein Problem sein könnte bin ich noch nicht
gekommen. (Damit hatte ich bisher noch nichts zu tun.)

Und ja, die Ausgabe ist im Prinzip fast das gewünschte Ergebnis. Bis auf
die nachfolgende F-Zeile, dort hat noch jemand wenige Zeichen am
Zeilenanfang aufgegessen. =8-|

Soweit der Zwischenstatus. LG, Ralph
bloonix
 2007-06-26 15:12
#77800 #77800
User since
2005-12-17
1615 Artikel
HausmeisterIn
[Homepage]
user image
[quote=RalphFFM,26.06.2007, 13:07]Und ja, die Ausgabe ist im Prinzip fast das gewünschte Ergebnis. Bis auf
die nachfolgende F-Zeile, dort hat noch jemand wenige Zeichen am
Zeilenanfang aufgegessen. =8-|[/quote]
Sorry, bei meinen vielen Tests und hin und her kopiererei wurde das
Original verändert... das Codestück macht das, was es machen soll. ;)

Hier nochmal ein Test mit dem Original:

AAAAAAA¡aaaaaaa¡aaa
BBBB¡bbbb¡bbb
CCCCCC¡cccc¡ccc
DDDDDDDD¡ddddd¡dddd
E-E-E¡eeeeeeeeee¡eee
FFFFFFFF¡fffff¡ff
GGGGGG¡ggggggggggggg¡ggg
HHHHH¡hhhhh¡h
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.
<< |< 1 2 >| >> 13 Einträge, 2 Seiten



View all threads created 2007-06-25 11:09.