V posledním díle o práci se soubory
naleznete mimo jiné čtení z adresářů a ukázku rekurze.
28.4.2006 09:00 | Jiří Václavík | přečteno 25186×
Mimo textových souborů, kterými jsme se zabývali v předchozích dílech, existují jiné. Nejdůležitější z nich jsou adresáře, na něž přichází řada právě dnes. Později se v tomto seriálu objeví i další typ souboru, kterým je socket.
Funkce link (tvrdý odkaz) a symlink (symbolický odkaz) fungují podobně jako unixovský příkaz ln. Obě funkce přijímají jako 1. argument soubor, na který se bude odkazovat a 2. argument jako název odkazu.
symlink("soubor", "odkaz") or die "Odkaz nebyl vytvořen: $!";
Relativní cestu skutečného umístění souboru po zadání odkazu vrací funkce readlink.
print readlink "odkaz";
Pro práci s binárními daty je třeba použít na ovladač funkci binmode, která ho přepne na binární režim. Poté už s ovladačem můžeme normálně pracovat.
binmode OVLADAC;
S adresáři se stejně jako u ostatních typů souborů pracuje prostřednictvím ovladačů. Opět je nutné adresář nejdříve otevřít. K tomu slouží funkce opendir, jejíž syntaxe se podobá funkci open. Čtení z adresáře provede funkce readdir a zavření closedir. readdir vrací v seznamovém kontextu seznam souborů a ve skalárním kontextu vrátí s každým voláním jednu položku adresáře. Následující kód vypisuje obsah kořenové složky a využívá seznamový kontext.
$, = ", ";
opendir(DIR, "/");
print readdir(DIR);
closedir DIR;
Zkusíme napsat program, který vypíše všechny soubory ze zadaného adresáře a určí zda se jedná o obyčejný soubor, adresář, symbolický odkaz nebo ještě něco jiného.
my $dir;
print "Zadej adresář, jehož strukturu chceš vytisknout: ";
chomp ($dir = <STDIN>);
opendir(DIR, "$dir") or die "Nepodařilo se otevřít $dir: $!";
while (my $pol = readdir DIR){
if (-f $dir."/".$pol){
print "F ";
}elsif(-d $dir."/".$pol){
print "D ";
}elsif(-l $dir."/".$pol){
print "L ";
}else{
print "X ";
}
print "$pol\n"
}
closedir DIR;
Nyní tento příklad ještě o něco vylepšíme. V případě, že bude soubor adresářem, vypíšeme i jeho obsah. Obsahem budou soubory, které vždy odsadíme o příslušný počet pomlček podle toho, jak hluboko jsme aktuálně v zanoření. To je mimo jiné i typická ukázka rekurze.
Napíšeme tedy podprogram, který bude vypisovat obsah adresáře a v případě, že nalezne podadresář, volá opět sám sebe. Jak jistě tušíte, problémy nastanou s otevíráním adresářů, u kterých na to nemáme právo. Protože jde pouze o demonstrační program, nebudeme tuto situaci řešit a v takovém případě program necháme ukončit.
my $dir;
print "Zadej adresář, jehož strukturu chceš vytisknout: ";
chomp($dir = <STDIN>);
tiskni_adresarovou_strukturu($dir);
sub tiskni_adresarovou_strukturu {
my($dir, $prefix) = @_;
my $fh;
opendir($fh, $dir) or die "Nepodařilo se otevřít $dir: $!";
while (my $pol = readdir $fh){
next if $pol eq "." or $pol eq "..";
if (-f $dir."/".$pol){
print "${prefix}F $pol\n";
}elsif(-d $dir."/".$pol){
print "${prefix}D $pol\n";
tiskni_adresarovou_strukturu($dir."/".$pol, $prefix."-");
}elsif(-l $dir."/".$pol){
print "${prefix}L $pol\n";
}else{
print " ";
}
}
}
Mimo readdir existují další 3 funkce, které využívají otevřený adresář.
Funkce | Význam |
seekdir(ovladač, pozice) | Nastavuje aktuální pozici v adresáři na pozici |
rewinddir(ovladač) | Nastavuje pozici na začátek |
telldir(ovladač) | Vrací aktuální pozici |
Pro výpis souborů (ať už obyčejných nebo podadresářů) z adresáře, které vyhovují danému vzoru, lze použít k tomu určenou funkci glob. Ta v seznamovém kontextu načte do pole seznam vyhovujících souborů.
@soubory = glob("*.pl"); #pole obsahuje jména souborů s příponou .pl v aktuálním adresáři
Ve skalárním kontextu vrací každé volání název dalšího vyhovujícího souboru. Následující příklad vypíše jména všech souborů v aktuálním adresáři:
while ($soubor = glob ("*")){
print $soubor."\n";
}
Ke stejnému účelu jako funkci glob lze využít operátor <> a to následujícím způsobem.
$, = ", ";
@soubory = <*.pl>;
print @soubory;
Nicméně operátor <> se touto možností poněkud tříští a většinou se dává přednost funkci glob. Pokud vám však hodně záleží na rychlosti, použijte přednostně kombinaci opendir, readdir, closedir, která je o něco rychlejší.
Funkce | Význam |
mkdir(jméno, práva) | vytvoří adresář |
rmdir(jméno) | smaže adresář |
chdir([jméno]) | změní pracovní adresář, je-li to možné. Pokud není jméno uvedeno, nastaví aktuální adresář podle $HOME |
Následující program bude vypisovat obsah zadaných adresářů, dokud budou zadávány. Každou iteraci cyklu bude změněn funkcí chdir aktuální adresář.
$, = " --- ";
print "Adresář: ";
while (<STDIN>){
if ($_ eq "\n"){exit;}
chomp;
print glob("*"), "\n\n" if (chdir $_);
print "Adresář: ";
}
Příští díl se bude věnovat možnostem formátování výstupu.