Hash aus Datei auslesen
Andreas Hoppe
- perl
0 Calocybe0 timothy0 Struppi0 Philipp Hasenfratz0 Andreas Hoppe0 Struppi0 Andreas Hoppe0 Struppi0 Andreas Hoppe0 Struppi
Hi Leute,
ich habe ein kleines Problem mit dem Auslesen von Daten aus einer Datei.
In meine Datei test.txt werden Einträge gespeichert. Jeder Eintrag wird mit Hilfe eines Hash %datensatz erstellt.
Das Ganze sieht momentan so bei mir aus:
my %datensatz = (Name => "Mustername", Email => "mustermail@nix.de");
open (DATEI, "<test.txt");
print DATEI %datensatz;
close (DATEI);
So weit so gut, funktioniert auch.
Aber wie kann ich die Datensätze wieder auslesen? Ich möchte die einzelnen Einträge in einem "Array of Hashes" haben.
Das Array deklariere ich mittels:
my @datensaetze = ();
Die Perl-Doku hilft mir da nicht allzuviel weiter. :-(
Grüße
Andreas
Moin!
Aber wie kann ich die Datensätze wieder auslesen? Ich möchte die einzelnen Einträge in einem "Array of Hashes" haben.
Wenn Du das vorher mit print %hash ausgibst, kannst Du das vergessen. Du wirst nicht drum herum kommen, Dir eine geeignete Datenstruktur auszudenken und entsprechende Input- und Output-Routinen zu schreiben. Falls das ganze aber so eine Art Datenbank-Tabelle sein soll, wo jeder Hash eine Zeile enthaelt, koennte Dir das Modul DBI in Verbindung mit DBD::CSV weiterhelfen.
So long
Hi!
Wenn Du das vorher mit print %hash ausgibst, kannst Du das vergessen. Du wirst nicht drum herum kommen, Dir eine geeignete Datenstruktur auszudenken und entsprechende Input- und Output-Routinen zu schreiben.
Das hab ich mittlerweile auch gemerkt. Einzig das Modul DB_File würde wohl diese Funktionalität bieten.
Grüße und Dank
Andreas
Hi Andreas
vielleicht hilft dir ja folgendes weiter:
aus
"Programming Perl"
by Larry Wall, Tom Christiansen & Randal L. Schwartz; ISBN 1-56592-149-6, 670 pages.
Second Edition, September 1996.
<snippet>
4.7.3 Arrays of Hashes
An array of hashes is called for when you have a bunch of records that you'd like to access sequentially, but each record itself contains key/value pairs. These arrays tend to be used less frequently than the other homogeneous data structures.
4.7.3.1 Composition of an array of hashes
@LoH = (
{
lead => "fred",
friend => "barney",
},
{
lead => "george",
wife => "jane",
son => "elroy",
},
{
lead => "homer",
wife => "marge",
son => "bart",
},
);
4.7.3.2 Generation of an array of hashes
while ( <> ) {
$rec = {};
for $field ( split ) {
($key, $value) = split /=/, $field;
$rec->{$key} = $value;
}
push @LoH, $rec;
}
while ( <> ) {
push @LoH, { split /[\s=]+/ };
}
while ( %fields = getnextpairset() ) {
push @LoH, { %fields };
}
while (<>) {
push @LoH, { parsepairs($_) };
}
$LoH[0]{pet} = "dino";
$LoH[2]{pet} = "santa's little helper";
4.7.3.3 Access and printing of an array of hashes
$LoH[0]{lead} = "fred";
$LoH[1]{lead} =~ s/(\w)/\u$1/;
for $href ( @LoH ) {
print "{ ";
for $role ( keys %$href ) {
print "$role=$href->{$role} ";
}
print "}\n";
}
for $i ( 0 .. $#LoH ) {
print "$i is { ";
for $role ( keys %{ $LoH[$i] } ) {
print "$role=$LoH[$i]{$role} ";
}
print "}\n";
}
for $i ( 0 .. $#LoH ) {
for $role ( keys %{ $LoH[$i] } ) {
print "element $i $role is $LoH[$i]{$role}\n";
}
}
</snippet>
Bye
Timothy
Hi Timothy,
reading from file
format: lead=fred friend=barney
while ( <> ) {
$rec = {};
for $field ( split ) {
($key, $value) = split /=/, $field;
$rec->{$key} = $value;
}
push @LoH, $rec;
}
wenn ich das richtig sehe, dann müssen in beiden "reading from file"-Beispielen die Daten vorher in der Art key=value gespeichert werden.
Ich behalt's aber mal im Auge, weil, so wie ich das sehe, sonst keine andere Möglichkeit besteht direkt an das Hash zu kommen.
Grüße und Danke
Andreas
Hi,
du willst 2 Dinge kennelernen.
Einmal
use Data::Dumper;
gibt dir deine Variabeln aus.
use Data::Dumper;
my %HASH = { bla => 1, blubb => 2};
open F, ...
print F Dumper %HASH;
close;
und einlesen:
open F ...
my $VAR1 = <F>;
eval ($VAR1);
my %HASH = %{$VAR1};
oder
use DB_File;
damit kannst du Hashes dierekt speichern.
us DB_File;
my %HASH;
tie %HASH , 'DB_File', 'datei', O_RDWR|O_CREAT, 0777;
%HASH{neu} = 'neuer Eintrag';
super Sache, vor allem in Verbindung mit Data::Dumper.
Struppi.
Halihallo Struppi
du willst 2 Dinge kennelernen.
use Data::Dumper;
gibt dir deine Variabeln aus.
Es gibt eine menschenlesbare Repräsentation der Datenstruktur aus, ja.
use Data::Dumper;
my %HASH = { bla => 1, blubb => 2};
Variablen sind keine Konstanten und werden klein geschrieben. Zudem, was wohl auf einen
Tippfehler zurückzuführen ist, schreibt man my %hash = () mit runden Klammern ;)
open F, ...
print F Dumper %HASH;
close;und einlesen:
open F ...
my $VAR1 = <F>;
eval ($VAR1);
my %HASH = %{$VAR1};
Äm, sorry, aber das ist zwar funktional aber völliger Schwachsinn.
Wenn du schon komplexe Datenstrukturen speichern willst, dann verwende
perldoc Storable;
aber ein aperformantes generieren eines schönen Abbildes der Datenstruktur und ein
aperformantes einlesen über kurriose eval's (was bei Attacken auch lauffähiger Perl-Code
sein könnte) ist schlicht, naja etwas viel "Overhead" ;)
oder
use DB_File;
schon besser ;)
super Sache, vor allem in Verbindung mit Data::Dumper.
Data::Dumper erstellt ein Dump, also Abbild einer Datenstruktur und ist somit _nicht_
für die Speicherung derselben gedacht.
Viele Grüsse
Philipp
PS: Nicht bös gemeint, aber Data::Dumper mit eval sollte man wirklich nicht verwenden,
auch wenn's auf den ersten Blick "schön einfach und lustig" aussieht.
Hi Philipp
open F, ...
print F Dumper %HASH;
close;und einlesen:
open F ...
my $VAR1 = <F>;
eval ($VAR1);
my %HASH = %{$VAR1};Äm, sorry, aber das ist zwar funktional aber völliger Schwachsinn.
Wenn du schon komplexe Datenstrukturen speichern willst, dann verwendeperldoc Storable;
aber ein aperformantes generieren eines schönen Abbildes der Datenstruktur und ein
aperformantes einlesen über kurriose eval's (was bei Attacken auch lauffähiger Perl-Code
sein könnte) ist schlicht, naja etwas viel "Overhead" ;)
Mhh, ich verstehe die Einwände. Aber
Bevor ich den Umstieg auf mySQL gewagt habe, habe ich meine "Datenbanken" immer so benutzt. Storable hat den Nachteil, das ich alle Daten einlesen muss, was wohl selbst bei einer kleinen DB nicht unbedeutsam ist.
eval sollte aber keine Probleme machen, da der Inhalt ja nicht ausgeführt wird, sondern der output von Data::Dumper, der (oder verläßt mich da meine Vorstellungskraft) keinen Code enthält, sondern Strings, die die Datenstruktur darstellt.
Struppi.
P.S. ich teile so viel Kritik aus, da sollte man durchaus auch Kritik einstecken können ;-)
Halihallo Struppi
Äm, sorry, aber das ist zwar funktional aber völliger Schwachsinn.
Wenn du schon komplexe Datenstrukturen speichern willst, dann verwendeperldoc Storable;
aber ein aperformantes generieren eines schönen Abbildes der Datenstruktur und ein
aperformantes einlesen über kurriose eval's (was bei Attacken auch lauffähiger Perl-Code
sein könnte) ist schlicht, naja etwas viel "Overhead" ;)
Bevor ich den Umstieg auf mySQL gewagt habe, habe ich meine "Datenbanken" immer so benutzt. Storable hat den Nachteil, das ich alle Daten einlesen muss, was wohl selbst bei einer kleinen DB nicht unbedeutsam ist.
Wieso? - Storable liest genauso die ganze Datei ein, wie du auch über deinen Lösungsweg
machen musst. Zudem hat Storable ein C-Backend, was es doch ganz schön schnell macht,
eval hingegen (wohl auch auf C basierend...) muss den eingelesenen String zuerst
parsen, dann wird er in einen Perl-Parsed-Tree umgewandelt und dann interpretiert, wie
das mit allen Perlprogrammen geschieht; das macht die Sache eben langsam.
eval sollte aber keine Probleme machen, da der Inhalt ja nicht ausgeführt wird, sondern der output von Data::Dumper, der (oder verläßt mich da meine Vorstellungskraft) keinen Code enthält, sondern Strings, die die Datenstruktur darstellt.
Auch Strings gehören zu Perl und werden interpretiert, genauso wie Befehle. Natürlich
gibt es bei Data::Dumper nicht viel "auszuführen", dennoch wird der Code (und _das_ ist
er dennoch) zuerst geparsed und dann interpretiert, ob dies nun eine Variablendeklaration
oder ein Befehl ist, spielt Perl eigentlich keine Rolle.
P.S. ich teile so viel Kritik aus, da sollte man durchaus auch Kritik einstecken können ;-)
Das musst du positiv sehen! Kritik ist da um zu lernen, also bitte "schlag auch bei mir
rein" ;)
Viele Grüsse
Philipp
Wieso? - Storable liest genauso die ganze Datei ein, wie du auch über deinen Lösungsweg
machen musst. Zudem hat Storable ein C-Backend, was es doch ganz schön schnell macht,
eval hingegen (wohl auch auf C basierend...) muss den eingelesenen String zuerst
parsen, dann wird er in einen Perl-Parsed-Tree umgewandelt und dann interpretiert, wie
das mit allen Perlprogrammen geschieht; das macht die Sache eben langsam.
Das eval langsam ist verkündige ich ja auch schon seit Jahren (vor allem bei JS).
Was ich meinte ist, du kannst mit Storable nur ein Variabel auf einmal speichern und lesen.
Und was ich nur im 1.Posting andeutete, verwende ich Data::Dumper und DB_File genmeinsam, um komplexere Strukturen abzuspeichern und zu laden. Also die einzelnen Strukturen des Hash per Dumper speichern und mit eval einlesen. Das ist herrlich flexibel (und ich hoffe bei meinen Datenbanken noch halbwegs performant)
Ich hab grad in der MLDBM Doku gelesen, das auch dort mit Data::Dumper gearbeitet wird, allerdings Storable (wegen Geschwindigkeit) empfohlen wird.
eval sollte aber keine Probleme machen, da der Inhalt ja nicht ausgeführt wird, sondern der output von Data::Dumper, der (oder verläßt mich da meine Vorstellungskraft) keinen Code enthält, sondern Strings, die die Datenstruktur darstellt.
Auch Strings gehören zu Perl und werden interpretiert, genauso wie Befehle. Natürlich
gibt es bei Data::Dumper nicht viel "auszuführen", dennoch wird der Code (und _das_ ist
er dennoch) zuerst geparsed und dann interpretiert, ob dies nun eine Variablendeklaration
oder ein Befehl ist, spielt Perl eigentlich keine Rolle.
Ja aber, der "code" wird ja erst erzeugt von Dumper und dann geparst.
use Data::Dumper;
my $test ="system dir";
my $VAR1 = Dumper($test);
eval $VAR1;
Da passiert nichts.
Struppi.
Halihallo Struppi
Was ich meinte ist, du kannst mit Storable nur ein Variabel auf einmal speichern und lesen.
Man braucht _nie_ mehr ;)
Und was ich nur im 1.Posting andeutete, verwende ich Data::Dumper und DB_File genmeinsam, um komplexere Strukturen abzuspeichern und zu laden.
Komplexität hat _gar nichts_ mit der "Anzahl von Variablen" zu tun. Ich kann dir eine
wunderschön Komplexe Datenstruktur in eine Variable packen... Im Gegenteil, es ist eben
nicht komplex und meistens unsauber programmiert, wenn man mehrere "Variablen" benötigt.
Du kannst mit einer Referenz auf einen Skalar, Array, Hash, Code, ... alles abbilden.
Das einzige, was Storable von Data::Dumper in unserem Sinne unterscheidet ist, dass
Storable eine Referenz als Input _erwartet_, bei Data::Dumper bist du da frei; dies als
Vorteil zu sehen ist jedoch falsch.
Also die einzelnen Strukturen des Hash per Dumper speichern und mit eval einlesen. Das ist herrlich flexibel (und ich hoffe bei meinen Datenbanken noch halbwegs performant)
Hast du dich wirklich über Storable informiert? - Das kann nämlich mindestens gleich
viel, ist jedoch noch wesentlich schneller.
Ich hab grad in der MLDBM Doku gelesen, das auch dort mit Data::Dumper gearbeitet wird, allerdings Storable (wegen Geschwindigkeit) empfohlen wird.
Aha, die werden sich wohl schon was dabei überlegt haben, oder? ;)
use Data::Dumper;
my $test ="system dir";
my $VAR1 = Dumper($test);
eval $VAR1;Da passiert nichts.
Eben doch. In $VAR1 hast du dann '$VAR1 = "system dir"' stehen und dieser Ausdruck,
wird zuerst geparsed, dann in einen Perl-Parsed-Tree umgewandelt und wie ein normales
Perl-Programm ausgeführt... Klar, dass der Befehl "system dir" nicht ausgeführt wird,
aber es findet ein allokieren von Speicher für die Variable $VAR1 statt, dann wird
ihr eine neue String-Konstante zugewiesen.
Das geschieht zwar auch etwa in Storable, nur dass da nicht der Perl-Parser anspringt und
versucht ein lauffähiges Script zu interpretieren, sondern ein sehr viel schlankerer
Code, der einfach gewisse Datenstrukturen einliest und _das_ ist der Geschwindigkeits-
gewinn (Stell dir vor: Dein eval $VAR1 überprüft gar die Syntax des Dumper outputs und
versucht den "Perl-Code" zu optimieren! - Bei Storable ist das ziemlich viel einfacher,
da man es _ausschliesslich_ mit Daten zu tun hat; der Output von Dumper _ist_ ein
_lauffähiges_ Perl-Programm).
Naja, ich glaube du hast jetzt verstanden, warum ich so gegen Data::Dumper interveniert
habe ;)
Viele Grüsse
Philipp
Hi,
erstmal Dank für Deine Antwort. Dem Data::Dumper-Ansatz kann ich leider nix abgewinnen.
us DB_File;
my %HASH;
tie %HASH , 'DB_File', 'datei', O_RDWR|O_CREAT, 0777;
%HASH{neu} = 'neuer Eintrag';
Nur dass das bei mir gerademal gar nicht funktioniert. Ich hab's mit den Beispielen aus der manpage probiert... :-((
Vielleicht versuch ich's nochmal.
Grüße
Andreas
Hi,
erstmal Dank für Deine Antwort. Dem Data::Dumper-Ansatz kann ich leider nix abgewinnen.
Ich benutz den als flexiblen DB Ersatz.
Du musst keine Felder definieren, und kannst alle Strukturen abspeichern und wieder laden.
Während DB_File halt nur einfache HASH Strukturen zuläßt.
Es gibt aber noch MLDBM ich weiss aber nicht, warum ich das nicht benutz habe, da muss es irgendeinen Haken geben.
us DB_File;
my %HASH;
tie %HASH , 'DB_File', 'datei', O_RDWR|O_CREAT, 0777;
%HASH{neu} = 'neuer Eintrag';
Nur dass das bei mir gerademal gar nicht funktioniert. Ich hab's mit den Beispielen aus der manpage probiert... :-((
Was funktioniert nicht?
DB_File ist nicht in allen Perl Versionen installiert, muss evtl. nach installiert werden.
Struppi.
N'Abend!
Ich benutz den als flexiblen DB Ersatz.
Du musst keine Felder definieren, und kannst alle Strukturen abspeichern und wieder laden.
Während DB_File halt nur einfache HASH Strukturen zuläßt.
Die mir ja reichen würden...
Nur dass das bei mir gerademal gar nicht funktioniert. Ich hab's mit den Beispielen aus der manpage probiert... :-((
Was funktioniert nicht?
Sobald ich einen Datensatz geschrieben habe, wird, wenn ich den nächsten schreiben will, immer der komplette erste Datensatz überschrieben.
Ich kann also immer nur einen Datensatz speichern. :-(
DB_File ist nicht in allen Perl Versionen installiert, muss evtl. nach installiert werden.
Doch, ist bei mir installiert, sonst würde mein #! /usr/bin/perl -w ja ganz schön meckern. :-)
Grüße und gute Nacht
Andreas
hehe, moin ;-)
N'Abend!
Ich benutz den als flexiblen DB Ersatz.
Du musst keine Felder definieren, und kannst alle Strukturen abspeichern und wieder laden.
Während DB_File halt nur einfache HASH Strukturen zuläßt.Die mir ja reichen würden...
Nur dass das bei mir gerademal gar nicht funktioniert. Ich hab's mit den Beispielen aus der manpage probiert... :-((
Was funktioniert nicht?
Sobald ich einen Datensatz geschrieben habe, wird, wenn ich den nächsten schreiben will, immer der komplette erste Datensatz überschrieben.
Ich kann also immer nur einen Datensatz speichern. :-(
Mein erstes Posting war ja voller Fehler (ich hahtte das nur so dahin gehackt), du hast das nicht so übernommmen?
Wie sieht denn dein Code aus, der nicht funktioniert?
Struppi.
Schon wieder fast N'Abend!
Sobald ich einen Datensatz geschrieben habe, wird, wenn ich den nächsten schreiben will, immer der komplette erste Datensatz überschrieben.
Ich kann also immer nur einen Datensatz speichern. :-(
Mein erstes Posting war ja voller Fehler (ich hahtte das nur so dahin gehackt), du hast das nicht so übernommmen?
Ne ne, ich habe nicht Dein Beispiel verwendet, sondern die, die in der manpage zu DB_File waren.
Und da war es dann so, dass ich zwar einen Datensatz speichern konnte (in einer 12 kB - Datei für 200 Zeichen Text), aber wenn ich dann einen Datensatz anhängen wollte, wurde der erste komplett überschrieben.
Wie sieht denn dein Code aus, der nicht funktioniert?
Moment, ich muss mal kurz man DB_File aufrufen...
use warnings ;
use strict ;
use DB_File ;
use vars qw( %h $k $v ) ;
unlink "fruit" ;
tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH or die "Cannot open file 'fruit': $!\n";
$h{"apple"} = "red" ;
$h{"orange"} = "orange" ;
$h{"banana"} = "yellow" ;
$h{"tomato"} = "red" ;
print "Banana Exists\n\n" if $h{"banana"} ;
delete $h{"apple"} ;
while (($k, $v) = each %h)
{ print "$k -> $v\n" }
untie %h ;
Das hat auch soweit funktioniert. Aber wenn ich dann erneut die Datenbank aufmachen will und neue Daten speichern will, habe ich die alten verloren.
Grüße
Andreas
unlink "fruit" ;
[..]
Das hat auch soweit funktioniert. Aber wenn ich dann erneut die Datenbank aufmachen will und neue Daten speichern will, habe ich die alten verloren.
Logisch, du weist was der Befehl da oben macht?
Struppi.