Multe programe Perl au de-a face cu fișiere text, cum ar fi fișiere de configurare sau fișiere log, deci ca să facem aceste cunoștințe utile este important să învățăm despre lucrul cu fișiere într-un stadiu timpuriu.
Să vedem mai întâi cum putem scrie într-un fișier, pentru că asta pare a fi mai ușor de făcut.
Înainte de a putea scrie într-un fișier trebuie să-l deschidem
cu open(), cerând sistemului de operare (Windows, Linux, OSX,
etc) să deschidă un canal de comunicație, pentru ca programul să poată
"vorbi cu" fișierul. Pentru asta Perl prevede funcția open
,
funcție care are o sintaxă puțin mai ciudată.
use strict;
use warnings;
my $filename = 'report.txt';
open(my $fh, '>', $filename) or die "Nu pot deschide fisierul '$filename' $!";
print $fh "Primul meu raport generat de Perl\n";
close $fh;
print "gata\n";
Acesta este un bun exemplu de lucru și ne vom întoarce la el, dar să începem cu un exemplu mai simplu:
Exemplu Simplu
use strict;
use warnings;
open(my $fh, '>', 'report.txt');
print $fh "Primul meu raport generat de Perl\n";
close $fh;
print "gata\n";
Aceasta necesită câteva explicații. Funcția open are 3 parametri.
Primul, $fh
, este o variabilă de tip scalar pe care am
definit-o în cadrul apelului funcției open()
. Am fi putut să
o definim mai devreme, dar de obicei este mai curat în felul acesta,
chiar dacă arată un pic mai ciudat la început. Al doilea parametru
definește modul de deschidere al fișierului. În acest caz, acesta
este semnul mai-mare (>
) acesta înseamnă că deschidem
fișierul pentru scriere. Al treilea parametru este calea către
fișierul pe care dorim să-l deschidem.
Când este apelată acestă funcție, Perl, pune un semn special în
variabila $fh
. Se numește file-handle (în limba engleză), o
referință către canalul de comunicare cu fișierul. Nu ne pasă prea
mult care este conținutul aceste variabile; vom folosi acestă
variabilă mai târziu. De reținut că ceea ce conține fișierul este
numai pe disc și NU în variabila $fh.
Odată fișierul deschis putem folosi file-handle-ul $fh
într-o
comandă print()
. Arată aproape la fel ca o
comandă print()
din celelalte părți ale tutorialului, dar
acum, primul parametru este file-handle și nu(!) este virgulă
după el.
Comanda print() de mai sus va printa textul în fișier.
Apoi cu linia următoare închidem file-handle-ul. Strict vorbind, acesta nu este o cerință în Perl. Perl va închide automat și curat toate referințele file-handle când variabilele nu mai sunt vizibile (en: out of scope), sau cel mai târziu la terminarea execuției scriptului. În orice caz, poate fi considerată o bună practică închiderea explicită a fișierelor.
Ultima linie print "gata\n"
este doar pentru ca următorul
exemplu să fie mai clar:
Gestionarea Erorilor
Să reluăm exemplul de mai sus și să înlocuim numele fișierului cu o cale inexistentă. De exemplu:
open(my $fh, '>', 'some_strange_name/report.txt');
Dacă rulezi scriptul acum vei primi un mesaj de eroare:
print() on closed file handle $fh at ...
done
De fapt acesta este doar o atenționare; scriptul rulează în continuare și de aceea vedem cuvântul "gata" printat pe ecran.
Chiar mai mult, am primit atenționarea doar pentru că am cerut
explicit acest lucru cu comanda use warnings
. Încercați să
comentați linia use warnings
și veți vedea că scriptul va
eșua în operațiunea de creare a fișierului în mod silențios. Deci nu
veți observa până când clientul, sau - mai rău - șeful vostru se va
plânge.
Oricum este o problemă. Am încercat să deschidem un fișier. Am eșuat dar totuși am încercat să printăm ceva în el.
Mai bine am verifica dacă open()
a fost cu succes înainte de
a continua.
Din fericire comanda open()
ea însăși returnează
ADEVĂR la
succes și FALS la eșec, deci putem scrie așa:
Open or die
open(my $fh, '>', 'some_strange_name/report.txt') or die;
Acesta este un idiom "standard": open or die. Foarte comun în Perl.
die
este un apel de funcție care va genera o excepție și
astfel va termina execuția scriptului.
"open or die" este o expresie logică. Așa cum știți din părțile precedente ale tutorialului, "or" scurtcircuitează în Perl (așa ca în multe alte limbaje). Acesta înseamnă că dacă partea dreptă returnează ADEVĂR, știm că întreaga expresie va fi ADEVĂRATĂ, și partea dreaptă nici nu mai este executată. Pe de altă parte dacă partea stângă este FALSĂ atunci și partea dreaptă este executată și rezultatul ei devine rezultatul întregii expresii.
În acest caz folosim acest scurtcircuit pentru a scrie expresia.
Dacă comanda open()
este cu succes atunci returnează ADEVĂR
și astfel partea dreaptă nu mai este executată. Scriptul continuă cu
linia următoare.
Dacă comanda open()
eșuează, atunci va returna FALS. Atunci
partea dreaptă a or
este de asemenea executată. Generează o
excepție, care termină scriptul.
În codul de mai sus nu verificăm rezultatul efectiv al operațiunilor logice. Nu ne pasă. Am folosit-o doar pentru "efectul secundar".
Dacă încerci scriptul cu modificările de mai sus vei obține un mesaj de eroare:
Died at ...
și NU va printa "gata".
O mai bună raportare a erorilor
În loc să apelăm "die" fără parametri, am putea adăuga câteva explicații despre ce s-a întâmplat.
open(my $fh, '>', 'some_strange_name/report.txt')
or die "Nu pot deschide fisierul 'some_strange_name/report.txt'";
va printa
Nu pot deschide fisierul 'some_strange_name/report.txt' ...
Este mai bine, dar al un moment dat cineva va încerca să schimbe calea la directorul corect...
open(my $fh, '>', 'correct_directory_with_typo/report.txt')
or die "Nu pot deschide fisierul 'some_strange_name/report.txt'";
... dar vei obține tot vechiul mesaj de eroare pentru că ei au modificat numai în apelul funcției open(), nu și în mesajul de eroare.
Este, probabil, mai bine de folosit o variabilă pentru numele fișierului:
my $filename = 'correct_directory_with_typo/report.txt';
open(my $fh, '>', $filename) or die "Nu pot deschide fisierul '$filename'";
Acum primim mesajul de eroare corect, dar tot nu știm de ce a eșuat.
Mergând cu un pas mai departe putem folosi $!
- o variabilă
integrată în Perl - pentru a printa ce ne-a transmis sistemul de
operare în legătură cu eșecul.
my $filename = 'correct_directory_with_typo/report.txt';
open(my $fh, '>', $filename) or die "Nu pot deschide fisierul '$filename' $!";
Rezultatul va fi
Nu pot deschide fisierul 'some_strange_name/report.txt' No such file or directory ...
Asta este mult mai bine.
Acum să ne întoarcem la exemplul original.
Mai-mare-decât?
Acel semn mai-mare-decât în apelul funcției open() ar putea fi puțin neclar, dar dacă ești familiarizat cu redirectarea în linia de comandă atunci acesta este similar. Altfel interpretează-o ca pe o săgeată care indică direcția curgerii datelor, în fișierul din partea dreaptă.
Caractere nelatine?
În cazul în care este nevoie să folosești caractere care nu sunt în tabelul ASCII, probabil vei dori să le salvezi ca UTF-8. Pentru acesta trebuie să înștiințezi Perl, că fișierul este codat UTF-8.
open(my $fh, '>:encoding(UTF-8)', $filename)
or die "Nu pot deschide fișierul '$filename'";