indietro

  • open FILEHANDLE,ESPR
  • open FILEHANDLE,MODO,ESPR
  • open FILEHANDLE,MODO,ESPR,LISTA
  • open FILEHANDLE,MODO,RIFERIMENTO
  • open FILEHANDLE

    Apre il file con nome ESPR, e gli associa FILEHANDLE.

    (Quella che segue èegue una documentazione completa di open(): per un'introduzione più semplice prendete in considerazione la lettura perlopentut).

    Se FILEHANDLE è una variabile scalare non definita (oppure un elemento di un array o di un hash), le viene assegnato un riferimento ad un filehandle anonimo, diversamente se FILEHANDLE è un'espressione, il suo risultato è usato come nome del filehandle voluto. (Questo potrebbe esser considerato come un riferimento simbolico, in questo caso use strict 'refs' potrebbe non essere efficace).

    Se EXPR viene omesso, verrà usata la variabile come scalare dello stesso nome di FILEHANDLE. (Si noti che le variabili lessicali, quelle dichiarate con my, non funzioneranno per questo scopo; in questo caso se usate my, specificate ESPR nella chiamata a open).

    Se vengono specificati tre o più argomenti la modalità di apertura e il nome del file sono separati. Se MODE è '<' oppure nulla, il file è aperto in lettura. Se MODE è ''> il file viene troncato e aperto in scrittura, oppure creato se necessario. Se MODE è '>'> il file viene aperto in append mode oppure creato se necessario ["append mode" significa scrittura dalla fine del file, NdT].

    Potete mettere un '+' davanti a ''> oppure '<' per indicare che intendete sia leggere che scrivere sul file; per questo '+<' è quasi sempre preferito per aggiornamenti in lettura/scrittura, la modalità '+'> prima troncherà il file. Di norma non potete usare la modalità di lettura/scrittura per aggiornare file di testo, dato che hanno una lunghezza di record non fissa. Controllate l'opzione -i in perlrun per un miglior approccio al problema. Il file viene creato con permessi 0666 modificati dalla umask impostata per il processo.

    Questi vari prefissi corrispondono ai parametri mode di fopen(3) 'r', 'r+', 'w', 'w+', 'a' e 'a+'.

    Nel caso d'uso a 2 argomenti (e 1 argomento) il MODE e il FILENAME devono essere concatenati (nel modo citato), possibilmente separati da spazi. Non è possibile omettere il MODE in questi casi se si intende usare '<'.

    Se il FILENAME inizia per '|' verrà interpretato come un comando al quale gli verrà inviato dell'output come pipe, e se FILENAME finisce per '|' verrà interpretato come un comando che invierà il suo output a noi. Consultate perlipc/"Using open() for IPC" ["Usare open() per IPC", NdT] per altri esempi su questo caso. (Non è ammesso l'uso di open per eseguire un comando e accedervi in scrittura e in lettura, consultate IPC::Open2, IPC::Open3 e perlipc/"Bidirectional Communication with Another Process" ["Comunicazioni bidirezionali con un altro processo", NdT] per delle alternative).

    Per tre o più argomenti, se MODO è '|-', il nome del file viene interpretato come un comando al quale gli verrà inviato dell'output come pipe e se MODO è '-|', il nome del file verrà interpretato come un comando che invierà il suo output a noi. Nel caso della versione a 2 argomenti (e 1 argomento), si dovrebbe sostituire il trattino ('-') con il comando. Consultate perlipc/"Using open() for IPC" ["Usare open() per IPC", NdT] per altri esempi su questo caso. (Non è ammesso l'uso di open per eseguire un comando e accedervi in scrittura e in lettura, consultate IPC::Open2, IPC::Open3 e perlipc/"Bidirectional Communication" ["Comunicazioni bidirezionali", NdT] per delle alternative).

    Nel caso della versione a tre o più argomenti della apertura delle pipe, se LIST è specificato (ulteriore parametro dopo il nome comando) allora LIST diventa la lista dei parametri da inviare al comando quando invocato, se la piattaforma in uso lo permette. Il significato di open con più di tre argomenti per chiamate diverse dalle pipe non è specificato. Alcuni "layers" sperimentali potrebbero fornire parametri ulteriori per dare significato a LIST.

    Nel caso della versione a 2 argomenti (e 1 argomento), l'apertura di '-' significa la lettura di STDIN mentre '-'> l'apertura di STDOUT.

    Potete usare i tre parametri per aprire specifici "strati" di IO (altrimenti noti come "disciplines" [letteralmente "ordini, discipline", NdT]) che verranno applicati all'handle, i quali modificano il funzionamento di come input e output vengono processatti (consultate open e PerlIO per ulteriori dettagli). Per esempio

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

    aprirà il file codificato UTF-8 contenente caratteri Unicode, si veda perluniintro. Va notato che se lo strato è specificato nel caso di tre parametri, gli strati impostati di default dalla direttiva open vengono ignorati.

    Open restituisce un valore diverso da zero in caso di successo, il valore indefinito diversamente. Se la open presenta una pipe, il valore restituito può essere il PID del processo figlio.

    Se si esegue Perl su un sistema che distingue fra file di testo e file binari, controllate binmode per alcuni consigli su come gestire questi casi. La chiave di distinzione fra sistemi che richiedono binmode e quelli che non lo richiedono è il loro formato di file di testo. Sistemi come Unix, Mac OS e Plan 9, che delimitano le linee con un singolo carattere, codificato in C come "\n", non richiedono binmode. Gli altri lo richiedono.

    Quando si apre un file, non è buona norma continuare la normale esecuzione se la chiamata fallisce, per questa ragione open viene frequentemente usata con die. Anche se die non farà quanto voluto (nel caso di script CGI, dove vorreste ottenere una pagina di errore formattata (ma ci sono dei moduli che possono aiutare con questo problema)) dovreste sempre controllare il valore restituito dalla apertura di un file. Fa eccezione il raro caso quando si intende usare un filehandle NON aperto.

    Un caso speciale, la versione a 3 argomenti in modalità lettura/scrittura dove il terzo parametro sia undef:

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

    che apre un filehandle su un file temporaneo anonimo. Inoltre, l'utilizzo di "+<" funziona per simmetria ma dovreste realmente considerare di scrivere prima qualcosa sul file temporaneo. Avrete la necessitè di utilizzare seek() per effettuare la lettura.

    A partire dalla version 5.8.0, il perl è stato compilato usando PerlIO di default. A meno che voi non abbiate cambiato questo aspetto (cioè Configure -Uuseperlio), potete aprire i filehandle in file "in memoria" mantenuti entro scalari Perl tramite:

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

    Tuttavia, se volete riaprire STDOUT oppure STDERR come file "in memoria", prima dovete chiuderli:

        close STDOUT;
        open STDOUT, '>', \$variabile or die "Impossibile aprire STDOUT: $!";

    Esempio:

        $ARTICOLO = 100;
        open ARTICOLO or die "Impossibile trovare l'articolo $ARTICOLO: $!\n";
        while (<ARTICOLO>) {...
        open(LOG, '>>/usr/spool/news/twitlog');	# (log e` riservato)
        # se la open fallisce, l'output viene perso
        open(DBASE, '+<', 'dbase.mine')		# aperto per aggiornare
    	or die "Impossibile aprire 'dbase.mine' per aggiornare: $!";
        open(DBASE, '+<dbase.mine')			# piu` rapidamente
    	or die "Impossibile aprire 'dbase.mine' per aggiornare: $!";
        open(ARTICLE, '-|', "caesar <$article")     # decodifica articolo
    	or die "Impossibile avviare caesar: $!";
        open(ARTICLE, "caesar <$article |")		# piu` rapidamente
    	or die "Impossibile avviare caesar: $!";
        open(EXTRACT, "|sort >Tmp$$")		# $$ e` il pid del nostro processo
    	or die "Impossibile avviare sort: $!";
        # in memory files
        open(MEMORY,'>', \$var)
    	or die "Impossibile aprire il file in memoria: $!";
        print MEMORY "pippo!\n";			# l'output andra` a finire in $var
        # processa la lista degli argomenti dei file insieme con ogni include
        foreach $file (@ARGV) {
    	process($file, 'fh00');
        }
        sub process {
    	my($nomefile, $input) = @_;
    	$input++;		# questo e` un incremento di stringa
    	unless (open($input, $nomefile)) {
    	    print STDERR "Impossibile aprire $nomefile: $!\n";
    	    return;
    	}
    	local $_;
    	while (<$input>) {		# si noti l'uso di indirezione
    	    if (/^#include "(.*)"/) {
    		process($1, $input);
    		next;
    	    }
    	    #...	        # qualunque cosa
    	}
        }

    Consultate perliol per informazioni dettagliate su PerlIO.

    Inoltre potete, nella tradizione della Bourne shell, specificare un EXPR che inizia con '&'>, nel qual caso il resto della stringa viene interpretato come un filehandle (o descrittore di file, se è numerico) per essere duplicato (come dup(2)) e aperto. Potete usare & dopo >, >>, <, +>, +>> e +<. La modalità che specificate deve essere uguale alla modalità del filehandle originale. (Duplicare un filehandle non entra nel merito dell'esistenza di precedenti buffer di IO). Se usate la versione a 3 argomenti, potete passare un numero, il nome di un filehandle oppure un normale "riferimento ad un glob".

    Ecco uno script che salva, redirige e ripristina STDOUT e STDERR usando diversi metodi:

        #!/usr/bin/perl
        open my $vecchioout, ">&STDOUT"     or die "Impossibile duplicare STDOUT: $!";
        open VECCHIOERR,     ">&", \*STDERR or die "Impossibile duplicare STDERR: $!";
        open STDOUT, '>', "pippo.out" or die "Impossibile redirezionare STDOUT: $!";
        open STDERR, ">&STDOUT"     or die "Impossibile duplicare STDOUT: $!";
        select STDERR; $| = 1;	# rendiamolo non bufferizzato
        select STDOUT; $| = 1;	# rendiamolo non bufferizzato
        print STDOUT "stdout 1\n";	# questo funziona
        print STDERR "stderr 1\n"; 	# anche per sottoprocessi
        open STDOUT, ">&", $vecchioout or die "Impossibile duplicare \$vecchioout: $!";
        open STDERR, ">&VECCHIOERR"    or die "Impossibile duplicare VECCHIOERR: $!";
        print STDOUT "stdout 2\n";
        print STDERR "stderr 2\n";

    Se specificate '<&=X', dove X è un numero descrittore di file, oppure un filehandle, allora Perl eseguirà l'equivalente della funzione C fdopen su quel descrittore di file (e non chiamerà dup(2)); questo è un modo d'uso più parsimonioso dei descrittori di file. Per esempio:

        # apertura in input, riutilizzando il fileno di $fd
        open(FILEHANDLE, "<&=$df")

    oppure

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

    oppure

        # apertura in aggiornamento, utilizzando il fileno di VECCHIOFH
        open(FH, ">>&=", VECCHIOFH)

    oppure

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

    Essere parsimoniosi sui filehandle è utile anche (al di là dell'essere parsimoniosi) per esempio quando qualcosa è dipendente dai descrittori dei file, come per esempio l'uso di lock tramite flock(). Se utilizzate semplicemente open(A, '>&B')>, il filehandle A non avrà lo stesso descrittore di file che ha B e quindi flock(A) non farà un flock(B) e viceversa. Ma con open(A, '>&=B')> il filehandle condividerà lo stesso descrittore di file.

    Va notato che se state usando un Perl più vecchio della 5.8.0., Perl userà la fdopen() della libreria C standard per implementare la funzionalità "=". Su molti sistemi Unix, fdopen() fallisce quando dei descrittori di file eccedono un certo valore, tipicamente 255. Per le versioni di Perl 5.8.0 e precedenti, PerlIO è molto spesso la norma.

    Potete vedere se il Perl è stato compilato con PerlIO eseguendo perl -V e cercando la linea userperlio=. Se useperlio è define, avete PerlIO, altrimenti no.

    Se aprite una pipe col comando '-', cioè sia con '|-' o '-|' con la versione a 2 argomenti (o 1) di open(), allora viene eseguita una fork implicita e restituito il pid del processo figlio per il processo padre, 0 al processo figlio. (Usate defined($pid) per determinare se la open ha avuto successo). Il filehandle si riconduce di norma al padre, ma l'input/output su quel filehandle viene passato attraverso pipe da/per lo STDOUT/STDIN del processo figlio. Nel processo figlio il filehandle non è aperto, l'input/output avviene dal/al nuovo STDIN o STDOUT. Solitamente questo viene usato come il normale open con pipe quando volete esercitare maggior controllo proprio su come viene eseguito il comando pipe, come quando state eseguendo setuid e non si vuole controllare il comando shell per i metacaratteri. Le seguenti triple sono più o meno equivalenti:

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

    Nell'ultimo esempio, in ogni blocco di codice viene mostrata la pipe come "list form" [un elenco di parametri, NdT], non supportato da alcuna piattaforma. Una buona regola è: se il vostro sistema operativo ha una vera fork() (in altre parole, se è UNIX) putete usare la list form.

    Consultate perlipc/"Safe Pipe Opens" ["Apertura sicura di pipe", NdT] per ulteriori esempi.

    A partire dalla versione 5.6.0, Perl tenta di svuotare i buffer, tutti i file aperti in output prima di qualsiasi operazione che potrebbe effettuare il fork, ma questo potrebbe non essere supportato su qualche piattaforma (si veda perlport). Per essere sicuri, dovreste impostare $| ($AUTOFLUSH nel modulo English) oppure chiamare il metodo autoflush() di IO::Handle su ogni handle aperto.

    Su sistemi che supportano i flag close-on-exec ["chiuso-su-esecuzione", NdT], il flag sarà impostato per ogni nuovo descrittore di file aperto, come determinato dal valore di $^F. Si veda perlvar/$^F.

    Chiudere uno qualsiasi dei filehandle di pipe provoca l'attesa del processo padre che il processo figlio finisca, restituendo lo stato in $?.

    Il nome del file passato nella chiamata alla open() nella versione con 2 argomenti (o 1) avrà gli spazi in testa e coda eliminati, e i normali caratteri di redirezione verranno onorati. Questa proprietà, nota come "magic open" ["apertura magica", NdT], può spesso essere usata con buoni esiti. Un utente potrebbe specificare un nomefile tipo "rsh cat file |", oppure voi potreste cambiare alcuni particolari nomifle in base alle necessità:

        $nomefile =~ s/(.*\.gz)\s*$/gzip -dc < $1|/;
        open(FH, $nomefile) or die "Impossibile aprire $nomefile: $!";

    Usate la versione della open a 3 argomenti per aprire un file che contiene strani caratteri arbitrari,

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

    oppure potrebbe essere necessario proteggere un qualsiasi spazio a inizio o fine nome:

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

    (questo potrebbe non funzionare su qualche bizzarro filesystem). Uno potrebbe scegliere, in coscienza, fra la versione magica e la versione a tre argomenti di open():

        open IN, $ARGV[0];

    permette all'utente di specificare un parametro della forma "rsh cat file |", ma non funziona su un nome file con uno spazio, mentre

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

    ha esattamente le restrizioni opposte.

    Se volete una "vera" open in stile C (consultate open(2) sul vostro sistema), dovrete usare la funzione sysopen, la quale non implica questo genere di "magia" (ma potrebbe usare alcuni differenti filemode rispetto alla open() del Perl, i quali sono mappati alla fopen() del C). Questa è un'altra possibilita per proteggere meglio il vostro nome file dalle interpretazioni. Per esempio:

        use IO::Handle;
        sysopen(HANDLE, $path, O_RDWR|O_CREAT|O_EXCL)
    	or die "sysopen $path: $!";
        $vecchiofh = select(HANDLE); $| = 1; select($vecchiofh);
        print HANDLE "Delle cose $$\n";
        seek(HANDLE, 0, 0);
        print "Il file contiene: ", <HANDLE>;

    Usando il costruttore dal package IO::Handle (oppure una delle delle sue sottoclassi, tipo IO::File oppure IO::Socket), potete generare filehandle anonimi che hanno come scope lo stesso di una qualsiasi variabile che possa contenere riferimenti, e automaticamente chiusi comunque, ogniqualvolta uscite da tale scope:

        use IO::File;
        #...
        sub leggo_miofile_munged {
    	my $TUTTO = shift;
    	my $handle = new IO::File;
    	open($handle, "miofile") or die "miofile: $!";
    	$primo = <$handle>
    	    or return ();     # Qui viene chiuso autimaticamente.
    	mung $primo or die "mung fallito";	# Oppure qui.
    	return $primo, <$handle> if $TUTTO;	# Oppure qui.
    	$primo;					# Oppure qui.
        }

    Consultate seek per qualche dettaglio riguardo la possibilità di mescolare letture e scritture.