Il linguaggio di programmazione Tcl ha diversi comandi per lavorare con i files.
Panoramica
Per l’apertura di un file si utilizza il comando open che vedremo in dettaglio più sotto.
Per la lettura e scrittura dei files su disco, o in memoria (file system virtuale), si utilizzano i seguenti comandi:
gets: per leggere datiputs: per scrivere dati
Se però i dati da leggere sono molti, ovvero se il file è molto grande, al posto del comando gets è preferibile utilizzare il comando read per caricare tutto il file, o un pezzo dello stesso, e poi magari suddividerlo in singole linee di testo con il comando split.
Quando si lavora con un file, Tcl si occupa di memorizzare costantemente la posizione del puntatore (pointer) del file. Per afferrare il concetto indicato dalla parola puntatore, possiamo rappresentarcelo come la puntina che legge e scrive i dati su un disco.
Tutti questi comandi, oltre che per i files su disco, possono essere utilizzati anche per le comunicazioni via rete (sockets) o per le comunicazioni tra processi (pipes).
Infine, per chiudere un file, o la comunicazione su un canale, si utilizza il comando close.
Tcl ci offre quindi una comodissima interfaccia uniforme per compiere le medesime operazioni al di là della effettiva risorsa interessata.
Comando open
# sintassi
open fileName ?access? ?permissions?
Il comando restituisce un identificatore (token) che ci permetterà in seguito di far riferimento con facilità alla risorsa utilizzata.
L’argomento ?access? specifica la modalità di accesso alla risorsa secondo questa tabella.
Modalità di accesso da utilizzare quando la risorsa già esiste
r | lettura
r+ | lettura/scrittura
a | scrittura con impostazione del puntatore alla fine della risorsa
Modalità di accesso da utilizzare quando la risorsa non esiste e la si vuole creare
w | scrittura*
w+ | scrittura*/lettura
a+ | lettura/scrittura* con impostazione del puntatore alla fine della risorsa
* Se la risorsa dovesse già esistere, gli eventuali dati verranno sovrascritti!
Nota: se l’argomento ?access? non viene specificato, il valore di default sarà r.
L’argomento ?permissions? è un valore intero ottale che specifica chi e come può accedere alla risorsa sulla base di specifici permessi. I valori più comuni sono:
0700lettura/scrittura/esecuzione limitata al solo proprietario (ideale per i files privati)0644lettura/scrittura per il proprietario, solo lettura per gli altri (ideale per i file di testo e dati)0666lettura/scrittura per tutti (è il valore di default)0755lettura/scrittura/esecuzione per il proprietario, lettura/esecuzione per gli altri (ideale per script ed eseguibili)
Comando close
# sintassi
close fileID
Il comando chiude il file identificato dall’identificatore fileID precedentemente aperto con il comando open.
Comando gets
# sintassi
gets fileID ?varName?
Il comando legge una linea di testo del file scartando i caratteri ASCII dell’accapo.
Nota: nei sistemi operativi GNU/Linux e macOS il carattere per l’accapo è il singolo line feed (10), nel sistema operativo Windows l’accapo è la combinazione dei caratteri carriage return e line feed (13 e 10).
Se indichiamo l’argomento facoltativo ?varName?, questo conterrà la linea di testo letta, ed inoltre il comando gets restituirà il numero dei caratteri letti o il valore -1 se siamo arrivati alla fine del file (End Of File).
Se invece non indichiamo l’argomento ?varName?, il comando gets restituirà la linea di testo letta, oppure una stringa vuota se nel file c’è una linea di testo vuota o siamo arrivati alla fine del file.
Il tipico ciclo per leggere un file di testo linea per linea
# esempio
set fileID [open "myfile.txt"]
while {[gets $fileID line] >= 0} {
...
}
Comando puts
# sintassi
puts ?-nonewline? ?fileID? myText
Il comando scrive la stringa di testo myText sullo stream identificato da fileID.
L’argomento
fileID, come abbiamo visto, può far riferimento per esempio ad un file precedentemente aperto con il comandoopen, ma potrebbe anche essere sostituito dalle parole chiavestdout(standard output) ostderr(standard error) che generalmente indicano lo schermo.
Se utilizziamo l’argomento -nonewline, allora vengono scartati i caratteri ASCII dell’accapo.
Comando read
Il comando read può essere utilizzato in diverse modalità.
I modalità
# sintassi
read ?-nonewline? fileID
Il comando restituisce tutto il contenuto del file (a partire dalla posizione del puntatore) in una singola stringa.
Se utilizziamo l’argomento -nonewline, allora vengono scartati i caratteri ASCII dell’accapo.
II modalità
# sintassi
read fileID numBytes
Il comando restituisce una stringa avente una lunghezza in bytes pari al valore indicato con l’argomento numBytes.
Comando seek
# sintassi
seek fileID offset ?origin?
Il comando cambia la posizione del puntatore all’interno del file identificato da fileID.
Nota: se il file è stato aperto in modalità di accesso a, allora il puntatore non può essere spostato, se invece il file è stato aperto in modalità di accesso a+, il puntatore può essere spostato all’inizio del file per poi procedere con la sua lettura.
L’argomento
fileIDpuò far riferimento ad un file precedentemente aperto con il comandoopen, ma potrebbe anche essere sostituito dalle parole chiavestdoutostderrche generalmente indicano lo schermo, oppure con la parola chiavestdin(standard input) che generalmente indica la tastiera.
L’argomento offset è un valore in byte che viene sommato alla posizione del puntatore. Di default il suo valore fa riferimento all’inizio del file, ma può far riferimento anche all’attuale posizione del puntatore, oppure alla fine del file in base al valore dell’argomento facoltativo ?origin?, che può quindi assumere i seguenti valori: start, current, end.
Comando tell
# sintassi
tell fileID
Il comando restituisce la posizione corrente del puntatore.
Comando flush
# sintassi
flush fileID
Elimina qualsiasi dato presente ancora nel buffer relativo alla risorsa indicata da fileID.
Comando eof
# sintassi
eof fileID
Il comando restituisce il valore 1 se la condizione di fine del file (end of file) si realizza, altrimenti restituisce il valore 0.
Promemoria su come Tcl accede ai files
Punti da ricordare:
- Il flusso di Input/output viene bufferizzato e quindi vi sono dei minimi ritardi nella trasmissione dei dati. Se per esempio il programma dovesse terminare in maniera imprevista, potrebbe verificarsi la condizione che, nonostante fossimo arrivati alla corretta chiusura di tutti i nostri files, siccome in realtà non erano ancora stati lavorati completamente tutti i dati, potremmo riscontrare alla fine una fastidiosa perdita di informazioni.
- Vi è un numero finito di file che si possono aprire contemporaneamente. Questo numero dipende dal sistema operativo su cui si sta lavorando. In generale, però, è possibile aprire diverse centinaia di file in contemporanea, ma occorre valutare molto bene questa opzione.
- Con il comando
getsnon è possibile distinguere una linea di testo vuota da una condizione di fine file. Con il comandoeof, invece, possiamo intercettare correttamente la condizione di fine file. - Tutti i comandi che abbiamo visto leggono esclusivamente dati testuali.
Nel prossimo articolo lavoreremo con le cartelle (directory).
