_  _   ,_
/^\/^\-/ @D
~(________/ PERL.LT
|L |L
L L
Straipsniai  Funkcijos 
Funkcijos/open - atidaryti failą, pipe ar deskriptorių
  • open FILEHANDLE,EXPR
  • open FILEHANDLE,MODE,EXPR
  • open FILEHANDLE,MODE,EXPR,LIST
  • open FILEHANDLE,MODE,REFERENCE
  • open FILEHANDLE

    Atidaro failą, kurio vardas yra perduodamas EXPR, ir susieja jį su FILEHANDLE.

    (Toliau seka išsami open() charakteristika. Norint paprastesnės, reikėtų atkreipti dėmesį į perlopentut.)

    Jei FILEHANDLE yra neapibrėžtas skaliarinis kintamasis (arba masyvas, arba hash elementas), kintamajam yr apriskiriama nuoroda į naują, nežinomą failo valdiklį, kitu atveju, jei FILEHANDLE yra išsireiškimas, jo reikšmė yr apanaudota kaip tikro norimo failo valdiklio pavadinimas. (Tai yra tariama simbolinė nuoroda, taigi use strict 'refs' neturėtų veikti.)

    Jei EXPR praleistas, skaliarinis kintamasis tokiu pačiu pavadinimu kaip ir FILEHANDLE turi failo pavadinimą. (Įsidėmėkite, kad leksiniai kintamieji - deklaruoti su my--neveiks šiam tikslai; taigi, jei naudojate my, įvardykite, kad atidarytų EXPR kvietime.)

    Jeigi trys ar daugiau argumentų yra aprašyti, tuomet atidarymo ir failo vardo režimai yra skirtingi. Jei MODE yra '<' arba nieko, failas yra atidaromas įvesčiai. Jei MODE yra '>' , failas yra nukertamas ir atidaromas išvesčiai, o esant reikalui sukuriamas. Jei MODE yra '>>' , failas yra atidaromas informacijos pridėjimui, vėlgi, esant reikalui, jis sukuriamas.

    Galima padėti '+' prieš '>' ar '<' parodyti, kad norima ir nuskaitymo ir rašymo priėjimo prie failo; taigi '+<' yra beveik visada paduodamas skaitymo/rašymo atnaujinimams - '+>' režimas pirmiausia nutrauks failą. Paprastai negalima naudoti abiejų nuskaitymo-įrašymo režimų tekstinių failų atnaujinimui, kadangiu jie turi kintamojo ilgio įrašus. Žr. -i perjungiklį perlrun geriasniam priėjimui prie to. Failas yra sukuriamas su 0666 leidimais, pakeičiamais proceso umask reikšmės.

    Šie įvairūs priešdėliai atitinka fopen(3) 'r' , 'r+' , 'w' , 'w+' , 'a' ir 'a+' režimus.

    2-argumentų (ir 1-argumento) kvietimo formoje, režimas ir failo vardas turėtų būti sujungtas (tokia tvarka), greičiausia atskirtas tarpų. Įmanoma praleisti režimą tose formose, jei režimas yra '<' .

    Jei failo vardas prasideda '|' , failo vardas yra interpretuojamas kaip komanda į kurią išvestis yra nu-pipe'inama, o jei failo vardas baigiasi '|' , failo vardas yra interpretuojamas kaip komanda, kuri nu-pipe'ina išvestį mums. Žr. "Using open() for IPC" perlipc'e dėl daugiau šito pavyzdžių. (Negalima open į komandą, kuri pipe'ina vidun ir išorėn, bet žr. IPC::Open2, IPC::Open3 bei "Bidirectional Communication with Another Process" perlipc'e dėl alternatyvų.)

    Trims ar daugiau argumentų, jei MODE yra '|-' , failo vardas yra interpretuojamas kaip komanda, į kurią išvestis bus nu-pipe'inta, o jei MODE yra '-|' , failo vardas yra interpretuojamas kaip komanda, kuri nu-pipe'ina išvestį mums. 2-argumentų (ir 1-argumento) formai reikėtų brūkšniuką ('-' ) pakeisti komanda. Žr. "Using open() for IPC" perlipc'e dėl daugiau pavyzdžių. (Negalima open į komandą, kuri pipe'ina vidun ir išorėn, bet žr. IPC::Open2, IPC::Open3 bei "Bidirectional Communication with Another Process" perlipc'e dėl alternatyvų.)

    Trijų ar daugiau argumentų formoje pipe'o atidarymo, jei LIST yra nurodytas (extra argumentai po komandos pavadinimo), tada LIST tampa argumentais iškviestai programai, jei pltaforma tai palaiko. open reikšmė su daugiau nei trimis argumentais ne-pipe'iniams režimams dar nespecifikuota. Experimentiniai "lygmenys" gali duoti papildomiems LIST argumentams reikšmę.

    2-argumentų (ir 1-argumento) formoje atidarymas '-' atidaro STDIN, o '>-' atvėrimas atidaro STDOUT.

    Galima naudoti trijų argumentų open formą nurodyti IO "lygmenius" (kartais taip pat vadinamus "disciplinomis") valdiklio panaudojimui, kuris paveikia, kaip įvestis ir išvestis yra vykdomos (žr. open ir PerlIO dėl daugiau detalių). Pavyzdžiui

      open(FH, "<:utf8", "file")

    atidarys UTF-8 užkoduotą failą, kuriame yra Unicode simbolių, žr. perluniintro. (Įsidėmėkite, kad jei lygmenys yra aprašyti trijų-argumentų formoje, pagrindinis lygmuo, nustatytas open pragmos yra tiesiog ignoruojamas.)

    Open gražina nenulinę reikšmę sėkmės atveju, kitu atveju - neapibrėžtumą. Jei open apima pipe'ą, gražinama reikšmė yra subproceso pid.

    Jei leidžiate Perl programą sistemoje, kuri skira tekstinius ir binarinius failus, tada vertėtų peržiūrėti binmode užuominoms kaip su tuo elgtis. Pagrindinis skirtumas tarp sistemų, kurioms reikia binmode ir tų, kurios neturi yra jų tekstinių failų formatai. Sistemos kaip Unix, Mac OS, ir Plan 9, kurios atriboja eilutes atskirais simboliais ir kurios užkoduoja tą simbolį C kaip "\n" , nereikia binmode. Kitoms to reikia.

    Atidarant failą, dažniausiai bloga mintis yra testi normalų vykdymą, jei užklausa nepavyko, taigi open dažnai naudojama kartu su die. Net jei die nepadarys, ko jūs norite (sakykime, CGI skripte, kur norite padaryti gražiai suformatuota klaidos žinutę (bet yra modulių, kurie gali padėti išspręsti šią problemą)) visada reikėtų patikrinti reikšmę, gražinamą iš failo. Nedažna išimtis yra darbas su neatidarytu failo valdikliu.

    Kaip specialus atvejis 3 argumentų forma su nuskaitymo/rašymo režimu ir trečiuoju argumentu undef:

        open(TMP, "+>", undef) ar die ...

    atidaro failo valdiklį anoniminiam laikinam failui. Taip pat "+<" naudojimas prideda simetrijos, bet visgi pirmiausia gerai apsvarstykite galimybe iš pradžių įrašyti ką nors į laikiną failą. Reikės seek() perskaitymui.

    Nuo v5.8.0, perlas turi pagal nutylėjimą PerlIO. Nebent tai pakeitėte (t.y. Configure -Uuseperlio), galima atidaryti failo vadiklius į "atminties" failus, laikomus Perl skaliaruose per:

        open($fh, '>', \$variable) || ..

    Nors, jei mėginsite iš naujo atidaryti STDOUT ar STDERR kaip "atminties" failą, pirmiausia reikės jį uždaryti:

        close STDOUT;
        open STDOUT, '>', \$variable or die "Can't open STDOUT: $!";

    Pavyzdžiai:

        $ARTICLE = 100;
        open ARTICLE or die "Can't find article $ARTICLE: $!\n";
        while (<ARTICLE>) {...
        open(LOG, '>>/usr/spool/news/twitlog');	# (log is reserved)
        # if the open fails, output is discarded
        open(DBASE, '+<', 'dbase.mine')		# open for update
    	or die "Can't open 'dbase.mine' for update: $!";
        open(DBASE, '+<dbase.mine')			# ditto
    	or die "Can't open 'dbase.mine' for update: $!";
        open(ARTICLE, '-|', "caesar <$article")     # decrypt article
    	or die "Can't start caesar: $!";
        open(ARTICLE, "caesar <$article |")		# ditto
    	or die "Can't start caesar: $!";
        open(EXTRACT, "|sort >Tmp$$")		# $$ is our process id
    	or die "Can't start sort: $!";
        # in memory files
        open(MEMORY,'>', \$var)
    	or die "Can't open memory file: $!";
        print MEMORY "foo!\n";			# output will end up in $var
        # process argument list of files along with any includes
        foreach $file (@ARGV) {
    	process($file, 'fh00');
        }
        sub process {
    	my($filename, $input) = @_;
    	$input++;		# this is a string increment
    	unless (open($input, $filename)) {
    	    print STDERR "Can't open $filename: $!\n";
    	    return;
    	}
    	local $_;
    	while (<$input>) {		# note use of indirection
    	    if (/^#include "(.*)"/) {
    		process($1, $input);
    		next;
    	    }
    	    #...		# whatever
    	}
        }

    Žr. perliol detalesnei informacijai apie PerlIO.

    Taip pat galite, Bourne apvalkalo (shell) tradicijoje, aprašyti EXPR pradžią su '>&' , kuriuo atveju likusi stringo dalis interpretuojama kaip failo valdiklio vardas (arba failo deskriptorius, jei skaitinis), kuris bus dublikuotas (kaip dup(2)) ir atidarytas. Galite panaudoti & po >, >> , < , +>, +>> ir +< . Nurodytas režimas turėtų atitikti originalaus failo valdiklio režimą. (Dublikuojant failo valdiklį nekreipiamas dėmesys į egzistuojančius IO buferius.) Jei naudojate 3 argumentų formą, galite peduoti arba skakčių, failo valdiklio vardą arba normalią "nuorodą į globalą".

    Štai skriptas, kuris saugo, nukreipia ir atstato STDOUT ir STDERR naudojant įvairius metodus:

        #!/usr/bin/perl
        open my $oldout, ">&STDOUT"     or die "Can't dup STDOUT: $!";
        open OLDERR,     ">&", \*STDERR or die "Can't dup STDERR: $!";
        open STDOUT, '>', "foo.out" or die "Can't redirect STDOUT: $!";
        open STDERR, ">&STDOUT"     or die "Can't dup STDOUT: $!";
        select STDERR; $| = 1;	# make unbuffered
        select STDOUT; $| = 1;	# make unbuffered
        print STDOUT "stdout 1\n";	# this works for
        print STDERR "stderr 1\n"; 	# subprocesses too
        open STDOUT, ">&", $oldout or die "Can't dup \$oldout: $!";
        open STDERR, ">&OLDERR"    or die "Can't dup OLDERR: $!";
        print STDOUT "stdout 2\n";
        print STDERR "stderr 2\n";

    Jei aprašysite '<&=X' , kur X yra failo deskriptoriaus numeris arba failo valdiklis, tada Perl elgsis kaip failo deskriptoriaus C fdopen (ir nekvies dup(2)); Šykščiau failų deskriptoriams. Pvz:

        # open for input, reusing the fileno of $fd
        open(FILEHANDLE, "<&=$fd")

    or

        open(FILEHANDLE, "<&=", $fd)

    or

        # open for append, using the fileno of OLDFH
        open(FH, ">>&=", OLDFH)

    or

        open(FH, ">>&=OLDFH")

    Buvimas menkesniu su failų valdikliais yra taip pat naudinga (be to menkumo), pvz., kai kas nors priklauso nuo failų deskriptorių, kaip pvz užrakinimas naudojant flock(). Jei tiesiog darote open(A, '>>&B') , failo valdiklis A neturės to paties failo deskriptoriaus kaip B ir tuo pačiu flock(A) ne flock(B), ir atvirkščiai. Bet su open(A, '>>&=B') failo valdikliai gali dalintis tuo pačiu failo deskriptoriumi.

    Įsidėmėkite, kad naudojant Perlą senesnį nei 5.8.0, Perlas naudos standartinės C bibliotekos fdopen() realizuoti "=" funkcionalumą. Daugelyje UNIX sistemų fdopen() nepavyksta, kai failo deskriptoriai peržengia tam tikrą ribą, dažniausiai 255. Perlams, vėlesniems nei 5.8.0, PerlIO dažniausia yra standartas.

    Galite patikrinti, ar Perlas buvo sukompiliuotas su PerlIO ar be paleisdami perl -V ir paieškokite useperlio= eilutės. Jei useperlio yra define , turite PerlIO, kitu atveju - ne.

    Jei atidarote pipe'ą komanda '-' , t.y. arba '|-', arba '-|' su 2-argumentų (ar 1-argumento) open() forma, tada padaromas besąlygiškas fork, o open gražinama reikšmė yra vaiko pid tėvo procese bei 0 vaikiniame procese. (Naudokite defined($pid) patikrinimui ar atidarymas buvo sėkmingas.) Failo valdiklis elgiasi normaliai tėvui, tačiau i/o į tą valdiklį yra nu-pipe'inama iš/į vaiko proceso STDOUT/STDIN. Vaikiniame procese failo valdiklis nėra atidarytas - i/o nutinka iš/į naują STDOUT ar STDIN. Paprastai tai naudojama kaip normalus pipe'intas open, kai norima pamėginti daugiau pakontroliuoti tiesiog pipe komandos vykdymą, pvz kai turite setuid, ir nenorite skanuoti apvalkalo komandų metasimboliams. Sekančios trijulės yra daugiau mažiau vienodos:

        open(FOO, "|tr '[a-z]' '[A-Z]'");
        open(FOO, '|-', "tr '[a-z]' '[A-Z]'");
        open(FOO, '|-') || exec 'tr', '[a-z]', '[A-Z]';
        open(FOO, '|-', "tr", '[a-z]', '[A-Z]');
        open(FOO, "cat -n '$file'|");
        open(FOO, '-|', "cat -n '$file'");
        open(FOO, '-|') || exec 'cat', '-n', $file;
        open(FOO, '-|', "cat", '-n', $file);

    Paskutinis pavyzdys kiekviename bloke parodo pipe'ą kaip "sąrašo formą", kas dar nepalaikoma visose platformose. Nykščio aukštyn taisyklė yra, jei platforma turi tikrą fork() (kitais žodžiais tariant, jei platforma yra UNIX) galite naudoti sąrašo formą.

    Žr. "Safe Pipe Opens" perlipc'e dėl daugiau šito pavyzdžių.

    Pradedant nuo v5.6.0, Perlas mėgina nuflushint visus atidarytus failus išvesčiai prieš bet kokią operaciją, kuri gali išsišakoti, bet tai gali būti nepalaikoma kai kuriose platformose (žr. perlport). Kad apsisaugotumėte, gali prireikti nustatyti $| ($AUTOFLUSH angliškai) arba iškviestiautoflush() IO::Handle metodą visiems atidarytiems valdikliams.

    Sistemose, kurios palaiko close-on-exec vėliavėlę failuose, vėliavėlė bus nustatyta naujai atidarytam failo deskriptoriui kaip nuspręsta $^F reikšmės. Žr. "$^F" perlvar'e.

    Uždarant pipe'inamą valdiklį lemia, kad tėvo procesas turi laukti vaiko iki kol jis baigs ir tada gražina būsenos reikšmę $? .

    Failo vardas, perduodamas 2-argumentų (ar 1-argumento) open() formai praras visus tarpus, o visi nukreipimo simboliai bus įvykdyti. Ši savybė, žinoma kaip "magic open", dažnai gali būti naudojama geriems rezultatams. Vartotojas galėtų nurodyti failo vardą "rsh cat file |", arba jūs galėtumėte pakeisti tam tikrus failų vardus kaip reikia:

        $filename =~ s/(.*\.gz)\s*$/gzip -dc < $1|/;
        open(FH, $filename) or die "Can't open $filename: $!";

    Naudokite 3-argumentų formą atidaryti failą su sutartinai keistais simboliais,

        open(FOO, '<', $file);

    kitu atveju būtina apginti priekyje ir gale esančius tarpus:

        $file =~ s#^(\s)#./$1#;
        open(FOO, "< $file\0");

    (tai gali neveikti kai kuriose įmantriose failų sistemose). Visgi reikėtų sažiningai pasirinkti tarp magic ir 3-argumentų open() formos :

        open IN, $ARGV[0];

    leis vartotojui nurodyti formos argumentą "rsh cat file |" , bet neveiks su failo vardu, kuris turės jį sekančius tarpus, nebent

        open IN, '<', $ARGV[0];

    turės lygiai priešingus apribojimus.

    Jei norite "tikro" C open (žr. open(2) savo sistemoje), tada reikėtų naudoti sysopen funkcija, kuri niekaip nesusijusi su magija (bet turi kiek skirtingus failų režimus nei open(), kuris tiesiogiai susijęs su C fopen()). Tai dar vienas būdas apginti failų vardus nuo interpretacijos. Pavyzdžiui:

        use IO::Handle;
        sysopen(HANDLE, $path, O_RDWR|O_CREAT|O_EXCL)
    	or die "sysopen $path: $!";
        $oldfh = select(HANDLE); $| = 1; select($oldfh);
        print HANDLE "stuff $$\n";
        seek(HANDLE, 0, 0);
        print "File contains: ", <HANDLE>;

    Naudojant konstruktorių iš IO::Handle paketo (ar vienos jo subklasių, kaip kad IO::File ar IO::Socket), galite generuoti anoniminius failų valdiklius, kurių sritis yra visi kintamieji, turintys nuorodas į juos ir automatiškai užsidarantys, palikus sritį:

        use IO::File;
        #...
        sub read_myfile_munged {
    	my $ALL = shift;
    	my $handle = new IO::File;
    	open($handle, "myfile") or die "myfile: $!";
    	$first = <$handle>
    	    or return ();     # Automatically closed here.
    	mung $first or die "mung failed";	# Or here.
    	return $first, <$handle> if $ALL;	# Or here.
    	$first;					# Or here.
        }

    Žr. seek dėl daugiau detalių apie skaitymo ir rašymo maišymą.

algirdas@perl.lt 2005.04.11 - $dabar