Thread Lesen Zeilen von einer Datei, verändern Zeilen in einer zweiten Datei (9 answers)
Opened by bora99 at 2016-11-22 11:45

Linuxer
 2016-11-22 23:22
#185638 #185638
User since
2006-01-27
3870 Artikel
HausmeisterIn

user image
Wie groß sind denn die Report-Dateien? Ein paar Kilobytes? Megabytes? Gigabytes?
Wie viele Daten davon würden in eine Status-Datei geschrieben werden?

Wenn das Kilobytes oder Megabytes sind, dann könnte man die Status-Infos erstmal in einer Variablen zwischenspeichern. Das würde die Vergleiche beschleunigen. In die Status-Datei wird dann nur geschrieben, wenn die aktuellen Werte noch nicht gesehen wurden.

Oder Du verwendest das Modul CPAN:Tie::File um die Status-Datei als Array einzubinden. Das senkt zwar nicht die notwendigen Zugriffe auf die Festplatte, aber es entlastet Dich von der Mühe, die Datei selber zu lesen und zu schreiben.


Variante 1:
more (9.2kb):

Code (perl): (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
#! /usr/bin/env perl
use strict;
use warnings;

use 5.010;

die "Usage: $0 report status\n" if 2 != @ARGV;

my $report_file = shift @ARGV;
my $status_file = shift @ARGV;

# hash for lookup of already seen datasets
my %seen;

# open report for reading
open my $rfh, '<', $report_file or die "open($report_file,<) failed: $!";
# open status for writing (appending), change to > for overwriting
open my $wfh, '>>', $status_file or die "open($status_file,>>) failed: $!";

LINE:
while ( my $line = <$rfh> ) {
    warn "(D) read: $line\n";

    # skip empty lines
    next LINE if $line =~ m/^\s*$/;

    chomp $line;
    # split into fields
    my ( $field1, $field2, $date1, $date2 ) = split m/\t/, $line;

    # no action if "date2" is not "-"; read next line
    next LINE if $date2 ne '-';

    # prepare a string to compare from first three fields
    my $to_save = join "\t", $field1, $field2, $date1;

    # check dataset (and register it). If not yet seen, write it to status file
    if ( ! $seen{ $to_save }++ ) {
        say $wfh $to_save;
    }

}

close $wfh or die "close($status_file) failed: $!;";
close $rfh;


__END__



Variante 2:
more (9.4kb):

Code (perl): (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
#! /usr/bin/env perl
use strict;
use warnings;

use 5.010;

use List::Util qw( first );
use Tie::File;

die "Usage: $0 report status\n" if 2 != @ARGV;

my $report_file = shift @ARGV;
my $status_file = shift @ARGV;


# open report for reading
open my $rfh, '<', $report_file or die "open($report_file,<) failed: $!";
# tie status file to array
tie( my @status, 'Tie::File', $status_file ) or die "Cannot tie $status_file: $!";

LINE:
while ( my $line = <$rfh> ) {
    warn "(D) read: $line\n";

    # skip empty lines
    next LINE if $line =~ m/^\s*$/;

    chomp $line;
    # split into fields
    my ( $field1, $field2, $date1, $date2 ) = split m/\t/, $line;

    # no action if "date2" is not "-"; read next line
    next LINE if     $date2 ne '-';

    # prepare a string to compare from first three fields
    my $to_save = join "\t", $field1, $field2, $date1;

    # write to status file if string has not been seen yet
    if ( ! first { $_ eq $to_save } @status ) {
        push @status, $to_save;
    }

}

close $rfh;


__END__



Zusätzlicher Gedanke:

Variante 1 ließe sich noch umgestalten, in dem man eine Prüfsumme von $to_save erstellt und diese in dem Hash %seen ablegt und den Vergleich dann über die Prüfsummen macht. Gerade wenn die Felder groß werden, könnte das ein Ansatz sein, um den Speicherbedarf geringer zu halten.

edit: fehlende Sprungmarken im Code ergänzt
Last edited: 2016-11-23 13:29:22 +0100 (CET)
meine Beiträge: I.d.R. alle Angaben ohne Gewähr und auf Linux abgestimmt!
Die Sprache heisst Perl, nicht PERL. - Bitte Crossposts als solche kenntlich machen!

View full thread Lesen Zeilen von einer Datei, verändern Zeilen in einer zweiten Datei