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 dati
  • puts: 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:

  • 0700 lettura/scrittura/esecuzione limitata al solo proprietario (ideale per i files privati)
  • 0644 lettura/scrittura per il proprietario, solo lettura per gli altri (ideale per i file di testo e dati)
  • 0666 lettura/scrittura per tutti (è il valore di default)
  • 0755 lettura/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 comando open, ma potrebbe anche essere sostituito dalle parole chiave stdout (standard output) o stderr (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 fileID può far riferimento ad un file precedentemente aperto con il comando open, ma potrebbe anche essere sostituito dalle parole chiave stdout o stderr che generalmente indicano lo schermo, oppure con la parola chiave stdin (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 gets non è possibile distinguere una linea di testo vuota da una condizione di fine file. Con il comando eof, 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).