seek-Aufruf wird ignoriert
Bine
- perl
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
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
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:
#!/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
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
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.
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