Thread CSV-Datei ohne Modul schreiben
(15 answers)
Opened by Stuermchen at 2011-07-12 09:07
Nachfolgend drei Ansätze wie man es machen kann.
Ich habe es für Linux-Systeme umgesetzt, soll es auch unter Windows funktionieren so muss die Bestimmung der Gruppen/Nutzer anders ablaufen. Der Erste ist Speicher schonend, der Zweite ist schnell, und der Dritte ist objektorientiert. Die Herangehensweise ist grundsätzlich:
Der Nachteil, wenn man keine Daten vorhält ist, dass man die Daten immer wieder suchen muss. Hier werden die Dateien "/etc/passwd" und "/etc/group" für jedes Verzeichnis und jeden User erneut geöffnet, das kostet jedes mal Zeit. 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 #!/usr/bin/perl use strict; use warnings; # langsam aber speicherschonend my @dirs=qw( /home/shared /home/topeg /home/test /var/log); # erste zeile print ";".join(';',@dirs)."\n"; my %user_list; # alle User finden for my $dir (@dirs) { for my $user (get_user_for_dir($dir)) { $user_list{$user}=1; } } # alle user Ausgeben for my $user (sort(keys(%user_list))) { print "$user;"; # alle verzeichnisse durch gehen # und 1/0 setzen für diesen User my @list; for my $pos (0..$#dirs) { my $ok=0; # alle user für das verzeichnis durchgehen for my $ruser (get_user_for_dir($dirs[$pos])) { if($ruser eq $user) { $ok=1; last; } } $list[$pos]=$ok; } print join(';',@list)."\n"; } ######################################################################## # user für ein Verzeichnis sub get_user_for_dir { my $dir=shift; my @user; my $gid=get_gid_for_dir($dir); @user=get_user_for_gid($gid) if(defined($gid)); return @user; } # gid für ein verzeichnis sub get_gid_for_dir { my $dir=shift; my $gid=undef; $gid=(stat($dir))[5] if(-d $dir); return $gid; } # alle user zu einer gid sub get_user_for_gid { my $gid=shift; my $gfile='/etc/group'; my $ufile='/etc/passwd'; my @user; if(-e $gfile && open(my $fh, '<', $ufile)) { while(my $line=<$fh>) { chomp($line); my ($user,undef,undef,$fgid)=split(/:/,$line); if($fgid == $gid) { push(@user,$user); } } close($fh);directory } if(-e $gfile && open(my $fh, '<', $gfile)) { while(my $line=<$fh>) { chomp($line); my (undef,undef,$fgid,$user)=split(/:/,$line); if($gid == $fgid) { push(@user,split(/,/,$user)); last; } } close($fh); } return @user; } Hier werden alle Daten, wenn möglich nur einmal gelesen. Das füllt natürlich den Speicher, beschleunigt die Zugriffe auf die Daten aber enorm. 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 #!/usr/bin/perl use strict; use warnings; # schnell und speicherhungrig my @dirs=qw( /home/shared /home/topeg /home/test /var/log); # erste zeile print ";".join(';',@dirs)."\n"; # alle vorhandenen groups lesen my %gid_list=read_groups(); # alle User finden my %user_list; for my $pos (0..$#dirs) { my $dir=$dirs[$pos]; my $gid=get_gid_for_dir($dir); if(defined($gid) && exists($gid_list{$gid})) { for my $user (@{$gid_list{$gid}}) { $user_list{$user}->[$pos]=1; } } } # alle user Ausgeben for my $user (sort(keys(%user_list))) { print "$user;"; # iste lesen und sicher stellen, dass alle Zeilen geholt werden my @list=@{$user_list{$user}}[0..$#dirs]; # werte auf 1/0 setzen map{$_=$_?1:0}@list; print join(';',@list)."\n"; } ######################################################################## # gid für ein verzeichnis sub get_gid_for_dir { my $dir=shift; my $gid=undef; $gid=(stat($dir))[5] if(-d $dir); return $gid; } # alle user zu einer gid sub read_groups { my $gfile='/etc/group'; my $ufile='/etc/passwd'; my %gid_user; if(-e $gfile && open(my $fh, '<', $ufile)) { while(my $line=<$fh>) { chomp($line); my ($user,undef,$uid,$gid)=split(/:/,$line); push(@{$gid_user{$gid}},$user); } close($fh); } if(-e $gfile && open(my $fh, '<', $gfile)) { while(my $line=<$fh>) { chomp($line); my ($gname,undef,$gid,$user)=split(/:/,$line); push(@{$gid_user{$gid}},split(/,/,$user)); } close($fh); } return %gid_user; } Der Vorteil bei der Objektorientierung ist, dass man die Objekte leicht erweitern kann, ohne alle umschreiben zu müssen. Da auch Code gebündelt wird, ist es leichter Fehler zu beheben. Ich nutze hier drei Klassen:
directory ist zur Verwaltung eines Verzeichnisses gedacht. Über das Objekt kann man User finden, den pfad lesen, etc. user verwaltet einen Nutzer. gids veraltet die Groupids und die dazugehörigen user Alle Dateizugriffe werden gekapselt und 'versteckt'. Als Feature wird die Liste der Gruppen immer dann aktualisiert, wenn sich etwas in der Datei geändert hat. 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 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 #!/usr/bin/perl use strict; use warnings; # objekt orientiert my @dirs=map{ directory->new($_) }qw( /home/shared /home/topeg /home/test /var/log); # erste zeile print ';'.join(';', map{$_->path()}@dirs )."\n"; # alle user finden my %users; for my $dir (@dirs) { for($dir->user_list()) { $users{$_->name()}=$_; } } # alle user Ausgeben for(sort(keys(%users))) { my $user=$users{$_}; my @list=map{ $user->has_dir($_) }@dirs; print $user->name().";".join(';',@list)."\n"; } ######################################################################## ######################################################################## ######################################################################## package directory; my $gids; sub new { my $class=shift(); my $dir=shift; $gids=gids->new() unless($gids); return undef unless(-d $dir); bless({dir=>$dir},$class); } sub path { shift()->{dir}; } sub gid { my $self=shift; return (stat($self->path()))[5] if(-d $self->path()); return undef; } sub user_list { my $self=shift; return $gids->user_list($self->gid()); } sub has_user { my $self=shift; my $user=shift; return 0 unless($user); return 0 unless($user->isa('user')); for($self->user_list()) { return 1 if($_->name() eq $user->name()); } return 0; } ######################################################################## package user; sub new { my $class=shift; my $name=shift; bless({name=>$name},$class); } sub name { shift()->{name}; } sub has_dir { my $self=shift; my $dir=shift; return 0 unless $dir->isa('directory'); my $path=$dir->path(); unless(exists($self->{dirs}->{$path})) { $self->{dirs}->{$path}=$dir->has_user($self); } return $self->{dirs}->{$path}; } ######################################################################## package gids; sub new { my $class=shift(); my $gfile=shift() || '/etc/group'; my $ufile=shift() || '/etc/passwd'; return bless({ufile=>$ufile, gfile=>$gfile, user=>{}},$class); } sub user_list { my $self=shift; my $gid=shift; $self->_read_groups(); return () unless(defined($gid)); return () unless(exists($self->{gids}->{$gid})); return @{$self->{gids}->{$gid}}; } sub user { my $self=shift; my $name=shift; unless($self->{user}->{$name}) { $self->{user}->{$name}=user->new($name); } return $self->{user}->{$name}; } # alle user zu einer gid sub _read_groups { my $self=shift; # update wenn nötig if(!$self->{update_g} || !$self->{update_u} || !$self->{gids} || $self->{update_g} < (stat($self->{gfile}))[9] || $self->{update_u} < (stat($self->{ufile}))[9] || ref($self->{gids}) ne 'HASH') { my %gid_user; if(-e $self->{ufile} && open(my $fh, '<', $self->{ufile})) { while(my $line=<$fh>) { chomp($line); my ($user,undef,$uid,$gid)=split(/:/,$line); $user=$self->user($user); push(@{$gid_user{$gid}},$user); } close($fh); $self->{update_u} = (stat($self->{ufile}))[9] } if(-e $self->{gfile} && open(my $fh, '<', $self->{gfile})) { while(my $line=<$fh>) { chomp($line); my ($gname,undef,$gid,$users)=split(/:/,$line); for my $name (split(/,/,$users)) { my $user=$self->user($name); push(@{$gid_user{$gid}}, $user); } } close($fh); $self->{update_g} = (stat($self->{gfile}))[9]; } $self->{gids}=\%gid_user; } } |