Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]6245[/thread]

Probleme mit Perl-Skript und der Skriptperformance



<< |< 1 2 >| >> 15 Einträge, 2 Seiten
Gast Gast
 2004-05-10 16:28
#82185 #82185
Hallo zusammen!

Habe ein Problem mit einem Perl-Skript:

Eine Datenbank-Export Datei (ascii-Datei) mit ca. 15.000 Datensätzen und einer Größe von
ca. 500Mb, bei welcher sich zwischen jedem Datensatz eine
Zeile mit einem $-Zeichen als Trennhinweis befindet, möchte ich in jeden
einzelnen Datensatz zerlegen/zerschneiden lassen (also in ca. 15.000 einzelne Dateien).
Dazu nimmt das Script einfach den Text zwischen zwei Trennzeilen und fügt diesen in eine
leere, neu-erstellte Datei ein, deren Name sich aus der zweiten Zeile eines jeden
Datensatzes ergibt!

Nun das Skript:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/perl -w
use strict;
$/ = qq{"\$"\t""\t""\n};
my $inputfile = 'C:\test.asc';
open A, $inputfile or die "Cannot open '$inputfile': $!";

while ( <A> ) {
my ($file) = /\n.*?"(.*?)"/ or next;
open B, "> $file.csv" or warn( "Cannot open '$file': $!" ), next;
print "[DEBUG] '$file': open ok\n";
chomp $_;
print B $_;
close B or warn( "Cannot close '$file': $!" ), next;
print "[DEBUG] '$file': close ok\n";
}



Eine Test-Datei (hier z.B. test.asc) könnte folgenden Inhalt haben (zwischen den "" befinden sich immer Tab-Vorschübe, keine Leerzeichen, wie es im Posting der Fall ist!):

"beginn erster Datensatz" "" ""
"text" "" ""
"texttexttexttetx text text" "" ""
"texttext text" "" "98387"
"text, text" "" ""
"text" "" ""
"" "" ""
"text" 0.00 0.00
"$" "" ""
"" "" ""
"mögliche Überschrift zweiter Datensatz" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.06.1999" ""
"$" "" ""
"" "" ""
"mögliche Überschrift dritter Datensatz" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" ""
"" "" ""
"mögliche Überschrift vierter Datensatz" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" ""


Wenn ich obiges Script nun bei einer kurzen Test-Datei ausführe funktioniert es auch
wunderbar und ich erhalte 4 Dateien mit den passenden Dateinamen (jeweils die zweite Zeile
eines Datensatzes).

Nun jedoch meine Fragen:
1. Wenn ich versuche das Script über die große 500Mb-Datei laufen lassen, bricht es nach
längerer Zeit ab und meldet 'Die Batch-Datei konnte nicht gefunden werden!'. Woran könnte
das liegen? Weitere Fehler-Meldungen werden nicht ausgegeben und Dateien werden auch nicht
erstellt!

2. Wie muss ich die Variable für die Trennzeile definieren, damit alle möglichen Varianten
der Trennzeilen abgedeckt werden, z.B.:
"$" "" ""
"$" "" "" ""
"$" "" "" "" ""
bisher wird ja nur "$" "" "" als Trennzeile erkannt. Weiss jedoch nicht, wie man diese Zeile möglichst Variabel gestalten könnte.

3. Kann es sein, dass dieses Skript zu Speicheraufwendig arbeitet? Habe jedoch keine
leider keine Ahnung, wie man es optimieren könnte :-(

Über Antworten zu den Fragen würde ich mich freuen!

Vielen Dank fürs Lesen und eventuelle Antworten!

Matthias

edit renee: [code]-Tags spendiert...\n\n

<!--EDIT|renee|1084192585-->
Crian
 2004-05-10 17:23
#82186 #82186
User since
2003-08-04
5871 Artikel
ModeratorIn
[Homepage]
user image
Irgendwas passt da nicht. Wenn Du Zeilenweise liest, musst Du sammeln, bis /^"\$/ zutrifft und das gesammelte dann ausgibst. So öffnest Du doch für jede Zeile eine Datei.


Edit: Ich würd es folgender Maßen machen

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/perl
use strict;
use warnings;

my @Buffer = ();

while (<DATA>) {
   push @Buffer, $_;
   if ($Buffer[-1] =~ /^"\$/) {
       if (@Buffer <= 1) {
           warn "Korrupte Daten vor Zeile $.";
       }
       else {
           (my $fn = $Buffer[1]) =~ s~^\s*"([^"]+).*$~$1~;
           unless (length $fn) {
               warn "Kann Dateinamen vor Zeile $. nicht ermitteln.";
           }
           else {
               chomp $fn;
               $fn .= '.csv';
               open(OUT, ">$fn") or die "Cannot open '$fn': $!";
               print "[DEBUG] '$fn': open ok\n";
               for my $buf (@Buffer) {
                   print OUT $buf;
               }
               close(OUT) or warn "Cannot close '$fn': $!";
               print "[DEBUG] '$fn': close ok\n";
           }
       }
       @Buffer = ();
   }
}

_ _DATA_ _
"beginn erster Datensatz" "" ""
"matthew01" "" ""
"texttexttexttetx text text" "" ""
"texttext text" "" "98387"
"text, text" "" ""
"text" "" ""
"" "" ""
"text" 0.00 0.00
"$" "" ""
"" "" ""
"matthew02" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.06.1999" ""
"$" "" ""
"" "" ""
"matthew03" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" ""
"" "" ""
"matthew04" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" ""


Wenn Du die Ende-Kennzeichnerzeilen nicht mit in den Datensätzen haben willst, alle Indizes von 0 bis $#Buffer-1 ausgeben.

Also

Code: (dl )
1
2
3
                for my $ind (0..$#Buffer-1) {
print OUT $Buffer[$ind];
}
\n\n

<!--EDIT|Crian|1084197757-->
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Gast Gast
 2004-05-10 17:36
#82187 #82187
Code: (dl )
$/ = qq{"\$"\t""\t""\n};

sieht irgendwie komisch aus ... was machen denn die " darin?
Ich denke wenn EOF durch $ repräsentiert wird, dann sollte ein schlichtes

Code: (dl )
1
2
local $/;
$/ = '$';

das Problem lösen können ...
Crian
 2004-05-10 18:03
#82188 #82188
User since
2003-08-04
5871 Artikel
ModeratorIn
[Homepage]
user image
... das löst das Problem an sich aber nicht, Lösung siehe oben Beitrag 2
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Matthew
 2004-05-10 18:08
#82189 #82189
User since
2004-05-10
5 Artikel
BenutzerIn
[default_avatar]
[quote=Crian,10.05.2004, 16:03]... das löst das Problem an sich aber nicht, Lösung siehe oben Beitrag 2[/quote]
Danke für die Hilfe!
Werde dein Skript nachher mal testen und dir dann nochmal Feedback geben!

@ Dieter: Die Hochkommas sind in der Export (=500mb)-Datei enthalten und repräsentieren die Spaltenanzahl des jeweiligen Datensatzes! Daran kann ich leider nichts ändern! Sie müssen also in die Definition der Datensatz-Umbruch-Zeile mit einbezogen werden..

Beste Grüße

Matthias
Crian
 2004-05-10 18:25
#82190 #82190
User since
2003-08-04
5871 Artikel
ModeratorIn
[Homepage]
user image
Mein Skript schmeißt sie in der zweiten Variante weg, die erste speichert die Ende-Rekords mit in den Dateien ab. Ich nehme mal an, Du brauchst Variante 2, dann musst Du die Ausgabenzeilen durch die unter dem Skript geposteten Zeilen ersetzen.
Bin mal gespannt, obs mit der großen Datei funktioniert. Ich bearbeite selbst große Dateien auf ähnliche Weise, bisher ohne Probleme.

Edit: Also so: (Hab das chomp auch nochmal verschoben, macht so mehr Sinn.)

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#!/usr/bin/perl
use strict;
use warnings;

my @Buffer = ();

while (<DATA>) {
   push @Buffer, $_;
   if ($Buffer[-1] =~ /^"\$/) {
       if (@Buffer <= 1) {
           warn "Korrupte Daten vor Zeile $.";
       }
       else {
           (my $fn = $Buffer[1]) =~ s~^\s*"([^"]+).*$~$1~;
           chomp $fn;
           unless (length $fn) {
               warn "Kann Dateinamen vor Zeile $. nicht ermitteln.";
           }
           else {
               $fn .= '.csv';
               open(OUT, ">$fn") or die "Cannot open '$fn': $!";
               print "[DEBUG] '$fn': open ok\n";
               for my $ind (0..$#Buffer-1) {
                   print OUT $Buffer[$ind];
               }
               close(OUT) or warn "Cannot close '$fn': $!";
               print "[DEBUG] '$fn': close ok\n";
           }
       }
       @Buffer = ();
   }
}

_ _DATA_ _
"beginn erster Datensatz" "" ""
"matthew01" "" ""
"texttexttexttetx text text" "" ""
"texttext text" "" "98387"
"text, text" "" ""
"text" "" ""
"" "" ""
"text" 0.00 0.00
"$" "" ""
"" "" ""
"matthew02" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.06.1999" ""
"$" "" ""
"" "" ""
"matthew03" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" ""
"" "" ""
"matthew04" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" ""


Edit2: Herzlich Willkommen, Matthew :-)\n\n

<!--EDIT|Crian|1084199411-->
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Matthew
 2004-05-10 18:38
#82191 #82191
User since
2004-05-10
5 Artikel
BenutzerIn
[default_avatar]
Hallo Crian!
Habe dein Skript eben mal ausprobiert, jedoch an einem externen Datenfile. Dort trat dann folgender Fehler beim ausführen auf:

Cannot open '"" "" "".csv': Invalid argument at C:\Skript_webforum.pl line 22, <A> line 354.

Dein Skript habe ich wie folgt verwendet:

[Edit: hab eben nochmal deine geänderte Version benutzt, die Trennzeilen brauche ich später nämlich nicht mehr; es gab aber immer noch den gleichen Fehler..]

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
#!/usr/bin/perl
use strict;
use warnings;
my $inputfile = 'C:\test.asc';
open A, $inputfile or die "Cannot open '$inputfile': $!";
my @Buffer = ();

while (<A>) {
push @Buffer, $_;
if ($Buffer[-1] =~ /^"\$/) {
if (@Buffer <= 1) {
warn "Korrupte Daten vor Zeile $.";
}
else {
(my $fn = $Buffer[1]) =~ s~^\s*"([^"]+).*$~$1~;
chomp $fn;
unless (length $fn) {
warn "Kann Dateinamen vor Zeile $. nicht ermitteln.";
}
else {
$fn .= '.csv';
open(OUT, ">$fn") or die "Cannot open '$fn': $!";
print "[DEBUG] '$fn': open ok\n";
for my $ind (0..$#Buffer-1) {
print OUT $Buffer[$ind];
}
close(OUT) or warn "Cannot close '$fn': $!";
print "[DEBUG] '$fn': close ok\n";
}
}
@Buffer = ();
}
}


Am Einlesen der Quelldatei kann es doch eigentlich nicht liegen, oder?

Viele Grüße

Matthias\n\n

<!--EDIT|Matthew|1084201108-->
renee
 2004-05-10 19:10
#82192 #82192
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
wie wär's hiermit:
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/usr/bin/perl
use strict;
use warnings;

my @Buffer = ();
my $i = 0;
while(my $line = <DATA>){
 $Buffer[$i] .= $line;
 $i++ if($line =~ /"\$("\s")+"$/);
 if($i == 20){
print2File(\@Buffer);
$i = 0;
  @Buffer = ();
}
}

sub print2File{
my ($buffer) = @_;
foreach my $set(@{$buffer}){
 my (undef,$name,undef) = split(/\n/,$set,3);
 ($name) = $name =~ /"([^"]+)/;
 $name =~ s/\s/_/g;
 open(W_FILE,">$name") or die $!;
 print W_FILE $set;
 close W_FILE;
}
}


"beginn erster Datensatz" "" ""
"matthew01" "" ""
"texttexttexttetx text text" "" ""
"texttext text" "" "98387"
"text, text" "" ""
"text" "" ""
"" "" ""
"text" 0.00 0.00
"$" "" ""
"" "" ""
"matthew02" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.06.1999" ""
"$" "" ""
"" "" ""
"matthew03" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" ""
"" "" ""
"matthew04" "" ""
"" "" ""
"texttext text" "5330146514" ""
"" "" ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" """ ""
"text, text" "" ""
"" "" ""
"text" "30.08.2000" ""
"$" "" """ ""
\n\n

<!--EDIT|renee|1084201894-->
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
Crian
 2004-05-10 19:26
#82193 #82193
User since
2003-08-04
5871 Artikel
ModeratorIn
[Homepage]
user image
[quote=Matthew,10.05.2004, 16:38]Cannot open '"" ""      "".csv': Invalid argument at C:\Skript_webforum.pl line 22, <A> line 354.[/quote]

kommt bei mir nicht, bei mir werden genauso die richtigen Dateien erzeugt. Probier mal das, was unter Data hängt, als Datei zu speichern. Sollte gehen.

@Renee: Den Index mitzuführen finde ich unelegant, was spricht gegen meinen Vorschlag?\n\n

<!--EDIT|Crian|1084202850-->
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
Crian
 2004-05-10 19:29
#82194 #82194
User since
2003-08-04
5871 Artikel
ModeratorIn
[Homepage]
user image
Aber der Fehler ist klar, Du hast da keinen Dateinamen in dem Datensatz. Den regulären Ausdruck sollte man so anpassen:

Code: (dl )
(my $fn = $Buffer[1]) =~ s~^\s*"([^"]*).*$~$1~;


(Stern statt Plus) dann kommt auch die Warnung.
s--Pevna-;s.([a-z]).chr((ord($1)-84)%26+97).gee; s^([A-Z])^chr((ord($1)-52)%26+65)^gee;print;

use strict; use warnings; Link zu meiner Perlseite
<< |< 1 2 >| >> 15 Einträge, 2 Seiten



View all threads created 2004-05-10 16:28.