Perl alapjai VI. - Fájlkezelés
Előző alkalommal a mintaillesztő kifejezésekről volt szó, s ennek kapcsán említettem, hogy a Perl egyik erőssége a szövegfeldolgozás. Szövegfeldolgozás azonban nem létezik fájlműveletek nélkül, hiszen az adatokat valahonnan be kell olvasni, s valahova ki kell menteni. Ebben a cikkben azt fogjuk áttekinteni, hogy milyen lehetőségeket ad a Perl a szöveges és bináris fájlkezelésre. Minden részletet nem fogunk tudni megismerni, de ígérem, így is bőven lesz olvasnivaló.
A következő programrészlet megnyit egy szöveges állományt, és kiírja a sorait a képernyőre:Az első sorban a
Az utolsó sorban megszüntetjük a hozzárendelést, azaz bezárjuk a fájlt. A megszüntetés nem szükséges, de illendő tevékenység, ha nem tesszük meg, akkor kilépéskor a Perl bezárja a nyitva maradt fájlokat.
A második sorban kerül beolvasásra és megjelenítésre a fájl tartalma. A kisebb és nagyobb jelek közé tett fájlazonosító szolgál egy sor beolvasására, gyakorlatilag ez a szöveges fájlból olvasás menete. Figyelnünk kell arra, hogy visszaadja a sortörés karakterét is (bármi legyen is az), tehát ha valóban csak a sor tartalmát szeretnénk, akkor egy
Ebben a sorban van egy trükk is, miszerint ha tömb környezetben hivatkozunk a fájl soraira, akkor az összes sor beolvasásra kerül, majd átadódik, szemben a skalár környezetben történő használattal, ahol csak a következő sor kerül beolvasásra. Példánkban azért kerül kiírása a teljes állomány, mert a formában hivatkozunk a fájlra, akkor egy sort, ha pedig formában, akkor a teljes fájlt, soronként a tömb egyes elemeihez rendelve tölti be.
Az fájlok írását a következőképpen valósíthatjuk meg Perl-ben:Az első és az utolsó sor hasonlít az előző példára, itt mivel írni akarjuk a fájlt, ezért a
A Perl nyelvben léteznek a standard kimenetre (alapértelmezett esetben képernyőre írás), a standard bemenetre (alapértelmezett esetben billentyűzetről bevitel) és a standard hibakimenetre (alapértelmezett esetben képernyőre írás) speciális, beépített fájlazonosítók. Ezek rendreHa ránézünk a programra, felfedezhetünk benne egy "hibát", az első
A következő sor beolvas egy sort a standard bemenetről (azaz alapértelmezett módon a billentyűzetről). A "beolvas egy sort" konkrétan azt jelenti, hogy addig fogad karaktereket, amíg egy
Végül egy
Mielőtt áttérnénk a nemzetközi vizekre, bemutatnék egy tipikus példát fájlfeldolgozásra, mely soronként beolvassa a fájlt, s valamilyen műveletet végez rajta. Jelen esetben megszámolja, hány olyan sora van, amelyben szerepel az, hogy "perl":A példából csak annyit magyaráznék meg, hogy a ciklusnak akkor lesz vége, mikor a fájl végére érkeztünk, s a cikluson belül az éppen aktuális sor mindig a
Az input és output szabályozásáért azEzt a négy sort együtt sohasem kell így használni, csak a lehetőségeket tekinthetjük át segítségükkel. Az első sor és a második sor azonos hatást vált ki: mind a kimeneti, mind a bemeneti műveletek során beállítja, hogy a kívülről érkező értékek utf8 kódolásuak. A harmadik sorban csak a kimenetet, a negyedik sorban pedig csak a kimenetet állítjuk utf8 kódolásúra. A Perl belső sztring ábrázolása Unicode az 5.6.0-s verzió óta, de automatikus konverziót végez minden alkalommal, ahol erre szükség van, így erről akár nem is lenne szükséges tudnunk. Nem vesszük észre azt, ha a programunk kódolása iso-8859-1 (vagy iso-8859-2), és mi egy ugyanilyen fájlba írunk, mivel a fájlműveletekhez ugyanazt a kódolást alkalmazza, ami a program kódolása (s amit a környezeti beállítások alapján határoz meg). Ha leírjuk egy programban, hogy akkor a Ha megnézzük, mi lesz a fájl tartalma egy hexadecimális editorral, akkor két byte-ot fogunk látni, az első a
Az történik, hogy aMost azt kapjuk - bármely környezetben is legyünk -, hogy a beolvasott karakter egy nagy Ő, azaz
A fent bemutatott 'utf8' sztringek helyett elég széles tárház áll rendelkezésünkre a különböző kódolásokból, gyakorlatilag bármely valószínűleg általunk használandó kódolást ismerni fog a Perl, amivel fordulunk hozzá.
Mielőtt rátérnénk ezek megismerésére, fontos szót ejteni a
Az olvasásra két utasítást használhatunk, az egyik a
A két utasítás között az a különbség, hogy a
Ha rendszerfájlokat próbálunk meg írni, akkor a
A fájlok végét a
Fontos parancs még a
A
Hasznos parancsok még a pack és az unpack, melyek segítéségével binárisra és binárisról kódolhatunk értékeket.
Végezetül fontos jeleznem, hogy "sima" és "sys" kezdetű függvényeket nem illik keverni, mert ha megtesszük, a bufferelés miatt nem várt következménye lehet a dolognak...
■ A sorozatban megjelent
- Perl alapjai I. - A múlt és a jövő
- Perl alapjai II. - Fejlesztői környezet, alapok
- Perl alapjai III. - Műveletek
- Perl alapjai IV. - Tömbök, hashek, elágazások, ciklusok és szubrutinok
- Perl alapjai V. - Mintaillesztő kifejezések
- Perl alapjai VI. - Fájlkezelés
- Perl alapjai VII.- Fájlműveletek
- Perl alapjai VIII. - Könyvtárműveletek
- Perl alapjai IX. - Adatbáziskezelés
Szöveges fájlkezelés, bemenet, kimenet
Ebben a részben az alapokat, majd a különböző nemzeti kódolásokat, beleértve az utf8-at fogjuk megtekinteni.Alapok
A szöveges fájlkezelés alapvetően a Perlben sincs másképpen, mint a többi nyelvben, azopen
és a close
parancsok játszanak központi szerepet. Az egyik különbség azonban, hogy a megnyitott fájlokhoz rendelt azonosítókra a Perl egy külön változótípust használ. Erről a típusról eddig nem volt szó, csak és kizárólag a fájlműveletekben van szerepe. A többi típustól eltérően nincs előtte se dollárjel, se más, ezek nélkül kell használnunk az azonosítót. A "hagyományok" szerint ezeket a változókat végig nagybetűkkel írjuk, azonban ez nem követelmény.A következő programrészlet megnyit egy szöveges állományt, és kiírja a sorait a képernyőre:
open(FILEID,'<proba.txt');
print <FILEID>;
close(FILEID);
FILEID
nevű (aminek lehetett volna bármilyen neve, ami egy változónak megengedhető, s lehetett volna kisbetűvel is írni, ahogy a korábbiakban említettem) fájlazonosítóhoz rendeljük hozzá az állomány megnyitásával magát az állományt (egy állomány több azonosítóhoz is hozzárendelhető). A későbbiekben ezzel az azonosítóval tudunk a "megnyitott" állományra hivatkozni. Az open
második paramétere az fájlnév, melyben a UNIX környezetben megszokott kisebb-nagyobb jeleket használhatjuk a megnyitási mód meghatározására. Példánkban olvasásra nyitjuk meg az állományt, ezért <
jelet írtunk. Megjegyzendő, hogy ha ezt elhagytuk volna a fájl neve elől, akkor is olvasásra nyílt volna meg az állomány. Amennyiben a >
jelet használtuk, akkor írásra nyitódik meg a fájl, s ennek következményeként a tartalma egyből el is veszett volna. Ha ezt nem szeretnénk, akkor lehetőségünk van még hozzáfűzésre is megnyitni a fájlt, ehhez a >>
jelet kell használnunk. Ezekre mindjárt nézünk példát is.Az utolsó sorban megszüntetjük a hozzárendelést, azaz bezárjuk a fájlt. A megszüntetés nem szükséges, de illendő tevékenység, ha nem tesszük meg, akkor kilépéskor a Perl bezárja a nyitva maradt fájlokat.
A második sorban kerül beolvasásra és megjelenítésre a fájl tartalma. A kisebb és nagyobb jelek közé tett fájlazonosító szolgál egy sor beolvasására, gyakorlatilag ez a szöveges fájlból olvasás menete. Figyelnünk kell arra, hogy visszaadja a sortörés karakterét is (bármi legyen is az), tehát ha valóban csak a sor tartalmát szeretnénk, akkor egy
chomp
parancs nem árt majd előtte.Ebben a sorban van egy trükk is, miszerint ha tömb környezetben hivatkozunk a fájl soraira, akkor az összes sor beolvasásra kerül, majd átadódik, szemben a skalár környezetben történő használattal, ahol csak a következő sor kerül beolvasásra. Példánkban azért kerül kiírása a teljes állomány, mert a
print
utasítás valójában egy tömböt (listát) vár, melynek összefűzve jeleníti meg az elemeit. Ha tehát $sor=<FILEID>;
@sorok=<FILEID>;
Az fájlok írását a következőképpen valósíthatjuk meg Perl-ben:
open(FILEID,'>proba.txt');
print FILEID "Hello World!";
close(FILEID);
>
jelet használtuk a fájl neve előtt. A második sorban látható, hogy a fájlba írásra a print
utasítást használtuk, mely után a fájl azonosító, majd - vessző nélkül! - a kiírandó lista következik. Az alapvető szöveges fájlműveleteket ezzel meg is ismertük, de van még mit tanulni. A Perl nyelvben léteznek a standard kimenetre (alapértelmezett esetben képernyőre írás), a standard bemenetre (alapértelmezett esetben billentyűzetről bevitel) és a standard hibakimenetre (alapértelmezett esetben képernyőre írás) speciális, beépített fájlazonosítók. Ezek rendre
STDOUT
, STDIN
és STDERR
nevűek. Ezek használata teljesen megegyezik a többi állományazonosítóéval, a különbség annyi, hogy nem kell megnyitni ezeket az open
, s nem kell lezárni a close
paranccsal. A következő kis program bekér egy nevet a felhasználótól, majd köszönti. Amennyiben nem adtunk meg nevet, a hiba kimenetre ír ki egy hibaüzenetet.
print "Hogy hívnak? ";
chomp($nev=<STDIN>);
if ($nev ne '') {
print STDOUT "Köszöntelek $nev!\n";
} else {
print STDERR "Nem adtál meg nevet!\n";
}
print
esetében nem írtuk oda, hogy milyen fájlba, hova szeretnénk kiírni az üzenetet, szemben a negyedik sorban levő print
utasítással. Ilyenkor, ahogy arról már korábbi cikkek keretében szó volt, a Perl egyszerűen kiírja a szöveget, a STDOUT
értéket veszi alapértelmezettnek.A következő sor beolvas egy sort a standard bemenetről (azaz alapértelmezett módon a billentyűzetről). A "beolvas egy sort" konkrétan azt jelenti, hogy addig fogad karaktereket, amíg egy
ENTER
t nem ütünk le (vagy nem szakítjuk meg a programot). A leütött ENTER
is a része lesz a bevitt értéknek, ezért is futtatunk le rajta egy chomp
utasítást, mely levágja azt a sor végéről.Végül egy
if
utasítás segítségével eldöntjük, írt-e be valamit a felhasználó, s ha igen, köszöntjük, ha nem, akkor pedig hibaüzenetet jelenítünk meg.Mielőtt áttérnénk a nemzetközi vizekre, bemutatnék egy tipikus példát fájlfeldolgozásra, mely soronként beolvassa a fájlt, s valamilyen műveletet végez rajta. Jelen esetben megszámolja, hány olyan sora van, amelyben szerepel az, hogy "perl":
$darab=0;
open (F, "fájlnév.txt");
while (<F>) {
$darab++ if /perl/;
}
close (F);
print "$darab előfordulás.\n";
$_
"topic" változóba kerül.Nemzetközi fájlkezelés
A Perl 5.8.0 megjelenésével a régi standard fájlkezelő motort nagyrészt a PerlIO nevű motor váltotta fel, mely lehetővé tesz transzparens konverziókat a ki- és bemeneti műveletek során. Ezeket teljességében ebben a cikkben nem tekintjük át (egy egész cikket is kitesz a téma), de egy rövid ízelítőt fogunk látni belőle.Az input és output szabályozásáért az
open
nevű "pragma" a felelős. A pragmák különböző dolgokra használhatóak, például lehetővé tesznek kötöttségeket a programozást illetően ("strict" pragma), stb. Az open pragma használata a következőképpen történik:
use open ':utf8';
use open IO => ':utf8';
use open OUT => ':utf8';
use open IN => ':utf8';
$nagyo="Ő";
$nagyo
változóba, ha a memóriatartalmat nézzük, akkor a nagy Ő betű Unicode megfelelője fog kerülni. Mindez addig nem lényeges azonban, amíg nem kerülünk szembe nemzetközi környezettel, s nemzetközi szövegfeldolgozással, ahol lehet, hogy olvasunk egy iso-8892-2 kódolású fájlból, míg írnunk egy utf8 kódolásúba kell. A sztringműveletek, miután a memóriában már jó kódolással vannak az adatok, már jól működnek, lássuk, hogy pontosan mi is történik, hogy ha használjuk ezt az "open" pragmát. A következő program a fájlba kiír egy nagy Ő betűt utf8 kódolással, majd beolvassa, s kiírja hexadecimálisan, hogy milyen értéket olvasott be.
use open OUT => ':utf8';
open(O, ">perlio.txt");
print O chr(0x150); # Ő
close O;
open(I, "<perlio.txt");
$input=<I>;
printf "%#x\n", ord(substr($input,0,1)), "\n";
printf "%#x\n", ord(substr($input,1,1)), "\n";
close I;
0xC5
, míg a második 0x90
. Ez a hosszú Ő megfelelője utf8 kódolással. A beolvasás viszont nagyban függ attól, hogy milyen környezetben futtatjuk a scriptet. Ha iso-8859-2, vagy iso-8859-1 környezetben (talán manapság még ez a jellemzőbb), akkor 0xc5
és 0x90
értékeket kapjuk vissza is. Ha esetleg utf8 környezetben vagyunk, akkor a 0x150
értéket.Az történik, hogy a
0x150
Unicode byte kódnak megfelelő hosszú Ő karaktert kiírjuk utf8 reprezentációban, majd visszaolvassuk úgy, mintha sima iso-8859-1 (vagy -2) kódolású lenne a fájl, s így két karaktert fogunk visszakapni. Ha beolvasni is helyesen szeretnénk a fájlt, akkor a következő program fog nekünk jól működni:
use open IO => ':utf8';
open(O, ">perlio.txt");
print O chr(0x150); # Ő
close O;
open(I, "<perlio.txt");
$input=<I>;
printf "%#x\n", ord(substr($input,0,1)), "\n";
close I;
0x150
. Programon "belül", legyen a beolvasott fájl bármilyen kódolásban, ha megfelelő kódolást állítottunk be a beviteli műveletekre, már helyesen tudunk dolgozni a sztringekkel.A fent bemutatott 'utf8' sztringek helyett elég széles tárház áll rendelkezésünkre a különböző kódolásokból, gyakorlatilag bármely valószínűleg általunk használandó kódolást ismerni fog a Perl, amivel fordulunk hozzá.
Bináris fájlkezelés
A Perl alapvetően a szöveges fájlokat kezeli, de (teljeskörű) lehetőséget kínál a bináris fájlkezelésre is. A kimenet általában itt sincs másként, mint a szöveges fájloknál, itt is aprint
utasítást használhatjuk (illetve a syswrite
-ot, erről mindjárt később). Az olvasásra és a fájlban történő mozgásra saját utasítások vannak.Mielőtt rátérnénk ezek megismerésére, fontos szót ejteni a
binmode
parancsról, mely ide kapcsolódik. Ennek egy paramétere van, a fájlazonosító. Ha ezt a parancsot "végrehajtjuk" a fájlazonosítón, akkor binárisként fogja kezelni az állományt. Ez azokon a rendszereken (pl. Windows) fontos, ahol a fájlok olvasásakor egyébként konverzió történne, s a soremelések átalakulnának (pl. Windows esetén a két bájtos 0x0d+0x0a-ról 0x0a-ra).Az olvasásra két utasítást használhatunk, az egyik a
read
, míg a másik a sysread
. Mindkettő paraméterezése azonos, első paraméterük a fájlazonosító, második egy skalár változó, melybe az olvasás történni fog, s a harmadik egy hossz paraméter, amennyi karaktert be szeretnénk olvasni. Egy negyedik paraméter is megadható, mely arra szolgál, hogy megmondja, a skalár változó mely pozíciójába fogjuk beolvasni a karaktereket. Mind a két olvasási lehetőségre hatással vannak az előbbiekben nemzetközi fájlkezelés keretében ismertetettek, azaz előfordulhat, hogy a hosszba 2-t írunk, s mégis 3 bájt beolvasása történik meg: lehet, hogy épp az egyik karakter egy utf8 karakter volt, két bájtnyi kódolással.A két utasítás között az a különbség, hogy a
read
bufferelt, azaz mondjuk úgy gyorsított előre tárazott fájlkezelést használ, míg a sysread
enélkül olvas. Az előbbit sima állományoknál, az utóbbit rendszerfájloknál ajánlott használni, mint például különböző eszközök olvasása.Ha rendszerfájlokat próbálunk meg írni, akkor a
print
helyett a syswrite
használata a célszerűbb, mely nincs bufferelve, s így egyből kiírásra kerül az általunk kiírni kívánt adat. Paraméterezése a sysread
paranccsal megegyező, azaz a fájlazonosítót, egy skalár változót és egy hosszt kell megadni, ekkor hossznyi karaktert fog kiírni a skalár változóból. Ha negyedik paraméterként megadunk egy értéket, akkor a skalár változóból attól a pozíciótól kezdve fogja ezt tenni.A fájlok végét a
eof
függvénnyel ellenőrizhetjük, mely igaz értéket ad vissza, ha a paraméteréül kapott fájlazonosítóhoz tartozó fájl olvasásának a végére értünk.Fontos parancs még a
seek
és a sysseek
melyek a fájlban való mozgásra használhatóak. Három paraméterük van. Az első a fájl azonosítóját, a második egy pozíció értéket, a harmadik pedig egy módot határoz meg. Ha a harmadik paraméter értéke nulla, akkor a második paraméterben megadott bájtpozícióra ugrik (erre a műveletre nincs hatással a nemzetközi beállítás!), ha egy, akkor az aktuális pozíció, plusz a megadott érték helyre, s ha kettő, akkor a fájl vége, plusz a megadott érték. Utóbbi esetben általában negatív értéket szoktak meghatározni a programozók, s a második esetben is van ennek értelme.A
seek
párja a tell
, mely azt mondja meg, hogy melyik bájtpozíción vagyunk az adott fájlban.Hasznos parancsok még a pack és az unpack, melyek segítéségével binárisra és binárisról kódolhatunk értékeket.
Végezetül fontos jeleznem, hogy "sima" és "sys" kezdetű függvényeket nem illik keverni, mert ha megtesszük, a bufferelés miatt nem várt következménye lehet a dolognak...
Nem nyitja meg a fájlt
Hibakezelés
-boogie-
<Nincs cím>
ne
" szocska? Vagy nem lehet ugy hogy&_nev
????Inkrementális
Amúgy a "not equal", azaz nem egyenlő rövidítése, és a karakteres nem egyenlő jele Perl-ben (a numerikus
!=
párja).-boogie-
áhhh
Perl levlista
-boogie-
file betöltés
pl.:
open(F, "http://valami.mas.hu/file.xml");
mindig azt írja ki, hogy nem létezik ilyen fájl. Mit lehet ilyenkor tenni?
(A gépen lévő fájlokkal tökéletesen működik, csak nem szeretném minden alkalommal
letölteni a fájlt, hogy a benne lévő adatokkal dolgozhasson a program.)
Előre is köszi a segítséget!