Concetti Chiave
- I file sono sequenze di byte memorizzate su memorie secondarie che, a differenza della memoria centrale, sono permanenti ma più lente.
- I record fisici sono unità di trasferimento fisse tra memoria di massa e memoria centrale, mentre i record logici, variabili, sono usati dalle applicazioni.
- Il trasferimento e la gestione dei file sono gestiti dal Sistema Operativo, che nasconde la frammentazione fisica dei file.
- I formati di file, come testo e binari, determinano come i byte sono organizzati e interpretati dai programmi.
- Le operazioni sui file si dividono in fisiche (gestite dal Sistema Operativo) e logiche (gestite dall'applicazione), influenzate dall'organizzazione logica scelta dal programmatore.
I File
Prima parte
File e memorie
Il termine file è una parola inglese che si può tradurre con archivio, ma che in Informatica più in generale indica una sequenza di byte residente su una memoria secondaria di un elaboratore. I file risiedono nelle memorie secondarie e sia l’essenza fisica sia il concetto stesso di file, sono strettamente legati ad esse. Cerchiamo di capire il perché riprendendo velocemente la definizione di memoria secondaria.
Esempi di memorie secondarie sono gli hard disk (o dischi rigidi, magnetici), le pen drive (pennette USB), i CD e i DVD (dischi ottici), le schede SD e microSD, i nastri magnetici per il backup dei dati,ecc.
Le memorie di massa però hanno il difetto della lentezza. Le memorie di massa sono estremamente più lente, al punto che per non rallentare eccessivamente il sistema, la CPU può avere direttamente accesso solo alla memoria centrale. Per questo motivo i dati memorizzati in un file possono essere utilizzati dalla CPU solo transitando prima attraverso la memoria centrale, trasferendo in essa le varie porzioni del file (blocchi) che di volta in volta sono necessarie al processo di elaborazione.
Record fisici e record logici
I blocchi in cui un file viene suddiviso durante i trasferimenti dalla memoria di massa a quella centrale e viceversa, sono detti record fisici e hanno una dimensione fissata, dipendente dalla struttura hardware dell’elaboratore. All’apertura di un file da parte di un'applicazione, viene stabilito un canale di collegamento con il file residente sulla memoria di massa. Esso viene concretamente realizzato utilizzando una porzione della memoria RAM, detta buffer di memoria, riservata per i trasferimenti dei record fisici di quel file da e verso la memoria di massa (vedi immagine). Si faccia attenzione a non confondere il record fisico prima definito, con il record inteso come struttura dati definita dal programmatore. Per non confondere i due concetti, riferendoci a quest’ultimo lo chiameremo record logico.
In definitiva, i blocchi o record fisici sono le unità di trasferimento nelle operazioni di I/O da/verso le memoria di massa, di dimensione fissata; i record logici, invece, sono le unità di trasferimento nelle operazioni di accesso al file da/verso le applicazioni che utilizzano il file e possono essere di dimensioni variabili perché, vedremo, a seconda delle esigenze del programma che si sta scrivendo, essi possono rappresentare singoli byte, righe di testo, strutture record, ecc.
Distinguendo fra record fisici e record logici secondo le precisazioni fatte, la situazione del buffer di memoria prima descritta, diventa quella della seconda figura. Quando la CPU, intendendo un'applicazione in esecuzione, richiede l’accesso ad un particolare record logico, nel buffer insieme ad esso viene caricato un certo numero di record logici, tanti quanti un record fisico è in grado di contenerne: questo numero è detto fattore di blocco.
I meccanismi che sovrintendono all'utilizzo dei file
Il trasferimento dei record fisici dalla memoria secondaria alla memoria centrale e viceversa, è affidato al Sistema Operativo e in particolare al File System, che si occupa di tutta la gestione fisica per l’archiviazione e l’accesso ai file sulle memorie secondarie. Se per l'applicazione e l’utente (punto di vista logico) solitamente un file è un’entità unica, in realtà invece può accadere che quel file sia frammentato in più parti che risiedono fisicamente in zone diverse e separate del supporto di memorizzazione. Questa situazione è molto comune in tutte le memorie di massa, ad eccezione dei nastri magnetici. Tra i compiti del Sistema Operativo rientra anche quello di rendere trasparente alle applicazioni e all’utente la reale suddivisione fisica dei file.
Prime riflessioni sui file
Abbiamo visto che a livello logico, cioè dal punto di vista di struttura dati e accesso ad essa da parte dei processi applicativi, un file può essere immaginato e utilizzato come una sequenza contigua di byte o anche di record logici. A livello fisico, invece, cioè dal punto di vista dell’hardware e della gestione da parte del Sistema Operativo, questa sequenza è frammentata in più parti e risiede fisicamente in zone diverse e separate del supporto di memorizzazione di massa.
Tutto ciò ha diversi vantaggi: a livello logico semplifica la vita al programmatore e, per come i file vengono gestiti a livello fisico, si potrebbe dire che un file non abbia limiti sulla dimensione che può raggiungere. L’unico limite verrebbe dettato dalla capacità in byte della memoria di massa in cui risiede, oltre che dalla capacità di gestione da parte del Sistema Operativo.
I file sono delle strutture dati che consentono di memorizzare grandi volumi di dati e per un periodo di tempo lungo a piacere.
Seconda parte
Il formato file
A seconda del contenuto informativo dei file, le sequenze di byte vengono organizzate in diversi formati. Il formato file indica la convenzione di codifica utilizzata per costruire la sequenza di byte di un file e in base alla quale è possibile dare il corretto significato ai byte in fase di lettura, attraverso un processo inverso di decodifica. Questa convenzione deve essere nota ai programmi utilizzatori, in modo che il contenuto del file letto possa essere correttamente interpretato.
I formati file per il testo, ad esempio, per rappresentare caratteri alfanumerici e segni di punteggiatura, usano vari sistemi di codifica, come i codici ASCII e UNICODE. Nei casi del codice ASCII essi stabiliscono una corrispondenza biunivoca fra l’insieme dei caratteri e l’insieme dei byte, assegnando a ciascun carattere di un testo un numero univoco, il codice, la cui rappresentazione in binario rappresenta il byte con cui quel carattere viene codificato nel file.
Le estensioni
Al formato è legata l’estensione di un file che è il suffisso del nome simbolico del file, sempre preceduto da un punto. L’estensione di un file rappresenta un metodo per indicare al Sistema Operativo quale è il formato file. Un esempio è quello dei sistemi Unix/Linux che all’interno del file utilizzano una sequenza di un certo numero di byte, detta magic number, normalmente posta prima della sequenza dei byte dei dati.
Anche se l'estensione non viene visualizzata, continua ad essere importante perché è in base ad essa che il Sistema Operativo automaticamente sceglie l'icona da attribuire al file e l'applicazione più adatta a gestire quel file.
Tipi di file: di testo e binari
Se si considera un file fisicamente, l’aggettivo binario potrebbe essere utilizzato per tutti i file, qualunque sia il suo formato. Tradizionalmente, però, considerando il formato si distinguono due categorie fondamentali di file: i file di testo e i file binari.
I file di testo sono dei file la cui sequenza di byte è organizzata in gruppi di un numero fissato di byte, dove ciascuno gruppo rappresenta la codifica di un carattere stampabile, alfanumerico o di punteggiatura, secondo una certa codifica. Per questo motivo, per leggere correttamente un file di testo, può bastare anche un semplice editor di testo, come "Blocco note”. Per terminare una riga nei sistemi Windows/MS-DOS si usa la sequenza dei caratteri ASCII carriage return (CR) e line feed (LF), mentre in quelli UNIX/Linux è sufficiente il carattere ASCII line feed (LF) e in quelli Mac-Os il carattere ASCII carriage return (CR). La figura mostra un esempio molto semplice di un file di testo creato su un sistema Windows/MS-DOS, aperto sia in un editor di testo standard, quale è il “Blocco note” di Windows, sia in un editor esadecimale. In quest’ultimo è possibile vedere direttamente la sequenza di byte del file, rappresentati in esadecimale (a ciascun coppia di cifre esadecimali corrisponde un byte). La figura evidenzia in giallo le sequenze di byte che codificano il carattere separatore di fine riga.
Vengono definiti file binari tutti i file che contengono anche byte che non vengono interpretati come caratteri. Per questa ragione i file binari in genere possono essere utilizzati solo dai programmi per i quali sono stati creati e se si prova ad aprirli con un editor di testo, si visualizza una lunga sequenza di caratteri strani senza alcun significato. Alcuni esempi di file binari sono i file di immagini, audio, video e di dati compressi.
La classificazione dei file nelle due categorie fondamentali file di testo e file binari, deriva dal considerare il formato file. Questa però non è l’unica classificazione possibile.
L’accesso ai file
Le operazioni sui file
Quando si parla di accesso ai file da parte di un’applicazione, generalmente si intende l’utilizzo di file di dati per compiere operazioni di scrittura e lettura. Si fa osservare che un accesso ad un file in scrittura, corrisponde ad una operazione di Output. Si ricorda, infatti, che la scrittura avviene su una memoria secondaria che è una periferica. Per la stessa ragione, un accesso ad un file in lettura corrisponde ad una operazione di Input. Le operazioni di I/O sono due operazioni fondamentali sui file, che combinate in vario modo, permettono di compiere tutte le operazioni tipiche della gestione di un archivio di dati, quali: inserimenti di nuovi dati
nell’archivio, aggiornamenti (o modifiche) di dati già inseriti, cancellazioni, ordinamenti, ricerche, ecc. Sarà questo il terreno su cui ci muoveremo nei prossimi articoli di approfondimento sui file.
Le operazioni di I/O e quelle che riguardano la gestione degli archivi, appartengono a due categorie diverse di operazioni sui file. Le prime infatti, lo abbiamo già discusso negli articoli precedenti, vengono gestite dal Sistema Operativo, le seconde invece vedremo vengono gestite dall’applicazione, ossia direttamente dal programmatore. Per distinguerle allora, le prime verranno chiamate operazioni fisiche sui file, le seconde operazioni logiche.
Le operazioni fisiche
Le operazioni fisiche sui file fondamentali sono:
• Creazione
• Apertura
• Lettura (o Input)
• Scrittura (o Output)
• Chiusura
La creazione di un file di solito avviene contestualmente al comando di apertura del file in scrittura quando esso non esiste: quando cioè il File System tenta di aprire in scrittura un file che non esiste, allora prima lo crea. Particolare attenzione invece deve essere posta quando si apre un file in lettura, perché se il file non esiste viene generato un errore di run-time, ossia un errore che non potendo essere rilevato durante la fase di compilazione, si manifesta solo durante l'esecuzione del programma e se non viene gestito dal programmatore, manda in crash l’applicazione.
Prima di poter effettuare una qualunque operazione su un file, il file deve essere aperto. Con l’operazione di apertura di un file, il Sistema Operativo crea nella memoria centrale il buffer di memoria per quel file (vedi articolo sui file), che verrà utilizzato per i trasferimenti da e verso la memoria di massa, dei blocchi (o record fisici) di dimensione fissata in cui il file è stato partizionato sulla memoria di massa. Da quel momento il Sistema Operativo si incaricherà di stabilire la corrispondenza tra i record fisici del file e i record logici dei dati, gestendo tutte le operazioni necessarie per le operazione di I/O sui record fisici che conterranno i record logici che di volta in volta saranno interessati da operazione di I/O da parte dell’applicazione.
Grazie a questo meccanismo il programmatore a livello logico vede il file come una struttura dati astratta composta da una sequenza di record logici, che costituiscono le unità di trasferimento (byte, righe di testo, strutture record, ecc.) coinvolte nelle singole operazioni di accesso al file da parte dell'applicazione e che in generale possono essere anche di dimensioni variabili; quest’ultima cosa dipenderà dall’organizzazione logica che il programmatore darà al file e lo preciseremo meglio nel prossimo paragrafo.
Con l’apertura di un file, inoltre, il Sistema Operativo inizializza un puntatore ai record logici del file, che in ogni momento servirà per fissare quale è la posizione nel file in cui verrà effettuata la prossima operazione di lettura o scrittura di un record logico, a meno che il puntatore non venga prima esplicitamente riposizionato dal programmatore, ammesso che ciò sia permesso. Questo puntatore, infatti, sarà inizializzato dal Sistema Operativo e potrà essere gestito in modi diversi a seconda del tipo di accesso e del tipo di organizzazione logica del file scelta dal programmatore (anche questo lo capiremo nel prossimo paragrafo). Vedremo così che alcuni tipi di file permetteranno il posizionamento del puntatore su una posizione a piacere all’interno del file, altri no. Per tutti questi motivi, quando si apre un file, sempre bisognerà specificare con quale modalità di accesso aprirlo e vedremo che: alcuni tipi di file potranno essere aperti o solo in scrittura o solo in lettura e per passare da una modalità all’altra, bisognerà sempre prima chiuderli e poi riaprirli cambiando modalità di accesso; altri tipi di file invece una volta aperti, indifferentemente permetteranno sia di scrivere, sia di leggere.
Durante l’apertura di un file, inoltre, ad esso viene associato un nome logico fornito dal programmatore con l’istruzione di apertura, di solito si tratta di un identificatore numerico o alfanumerico che il programmatore potrà utilizzare nel codice del programma per operare su quel file.
Con l'operazione di chiusura di un file, infine, prima di tutto il record fisico contenuto nel buffer di memoria dedicato a quel file, viene salvato nella memoria di massa; subito dopo il buffer di memoria viene deallocato liberando memoria. Bene, vediamo ora di capire come l'organizzazione logica che il programmatore sceglie per un file, possa influenzare i meccanismi e le modalità con cui le operazioni di Lettura/Scrittura potranno essere condotte su di esso.
L'organizzazione logica dei file e le modalità di accesso
Negli articoli precedenti abbiamo visto che un’applicazione che utilizza un file, grazie ai servizi messi a disposizione dal File System, ha una visione astratta del file che deriva dall'organizzazione che il programmatore dà alla sequenza di byte del file, in base alle
esigenze del programma che sta scrivendo. A tal proposito, se necessario vengono in soccorso del programmatore anche i concetti di campo e record. Un campo è costituto da un insieme di byte che può essere utilizzato per codificare una singola informazione che può essere numerica, come nel caso di un importo in euro, o alfanumerica, come nel caso di un codice fiscale o il nominativo di un cliente. Un record, invece, è costituito dall'insieme di byte che rappresenta un insieme di campi logicamente correlati tra loro.
A livello logico, dunque, un file può essere definito come una sequenza di record logici, in cui ciascuno di essi opportunamente organizzato dal programmatore, rappresenta l’unità di trasferimento, ossia l’insieme di byte coinvolti, nelle singole operazioni di I/O su un file da parte di un’applicazione. A seconda della scelta adottata dal programmatore, l'unità di trasferimento potrà essere rappresentata da un singolo byte, un riga di testo, un singolo campo, un record ecc. In generale, quindi, un record logico potrà avere una dimensione in byte costante o variabile.
In base a queste nuove definizioni, a livello logico i file possono essere distinti in due diverse categorie fondamentali: i file strutturati, in cui il contenuto informativo è organizzato in una sequenza di record (file di record); i file non strutturati, in cui di solito l'informazione è codificata in una sequenza di caratteri organizzata in righe separate da un fine riga.
Quando il programmatore fissa l’organizzazione logica di un file, uno degli aspetti più importanti che deve considerare è quello che riguarda la possibilità di reperire le informazioni all’interno del file, ossia il fatto che i dati in esso memorizzati devono poter essere letti e modificati. Si tratta di fornire al File System un modo per poter separare e distinguere i diversi record logici. Questa cosa può essere ottenuta adottando diverse soluzioni. Per esempio, nel caso particolare dei file strutturati, una di queste può consistere nel sfruttare la lunghezza in byte dei record. Quando il programmatore fissa la struttura record, per essa può scegliere una lunghezza costante o una lunghezza variabile. Scegliere di avere dei record a lunghezza costante, il che significa precisare il numero di byte destinati a ciascun campo in modo che tutti i record abbiano la stessa lunghezza in byte, sicuramente facilita il reperimento delle informazioni.
• Per il File System/Funzioni di libreria, diventa immediato capire dove finisce un record e ne inizia un altro, basta contare i byte di separazione. Si avrebbe così la possibilità di assicurare un accesso sequenziale ai diversi record, perché per passare da un record all’altro basta far partire il puntatore al file dall’inizio del file e spostarlo ogni volta di uno stesso numero di byte noto, pari alla lunghezza fissata per la struttura record.
• Se di un record si conosce la posizione nel file (il primo record avrà la posizione 1, il secondo la posizione 2 e così via), per il File System diventa addirittura possibile individuare il record fisico in cui esso si trova e, quindi, assicurare un accesso diretto al quel record. Il File System infatti potrà portare il puntatore al file, direttamente sull’indirizzo del record che può calcolare nel modo seguente:
indirizzo = lunghezza * (posizione -1) + 1
Per indirizzo di un record all’interno di un file, s’intende il numero di posto del primo byte di quel record (vedi figura di sotto). Nella formula di prima il termine (posizione -1) rappresenta il numero di record che precedono il record che stiamo considerando, che moltiplicato per la lunghezza costante in byte dei record, fornisce il numero di byte che precedono il record considerato; pertanto aggiungendo un’unità otteniamo proprio il numero di posizione del primo byte del record considerato e, quindi, il suo indirizzo.
Continuando l'esempio di prima, nel caso in cui invece per i record il programmatore scelga una lunghezza variabile, i campi omologhi fra record e, quindi, i record stessi, avrebbero dimensioni in byte diverse e senza altre precauzioni si avrebbero le seguenti conseguenze:
• Non sarebbe più possibile per il File System/Funzioni di libreria, separare i record contando il numero di byte, perché questo valore è variabile e non sarebbe così possibile fornire un accesso sequenziale;
• Il File System non sarebbe più in grado di posizionare il puntatore direttamente su un record logico di cui si conosce la posizione, perché non più in grado di calcolare il suo l’indirizzo e non sarebbe così possibile fornire un accesso diretto.
Nel caso di record logici a lunghezza variabile, le cose si complicano e senza entrare nei dettagli, diciamo solo che il programmatore deve ricorrere a delle tecniche particolari per recuperare i record logici. Queste tecniche potrebbero prevedere di separare le varie informazioni, inserendo nel file dei caratteri speciali, un carattere di fine record per separare i record e un carattere di fine campo per separare i campi, in modo da poter assicurare almeno un accesso sequenziale al file. Queste tecniche potrebbero altresì sfruttare un particolare tipo di accesso ai file, detto accesso binario, che consente di recuperare un record logico in modo simile all’accesso diretto, specificando però per esso non la sua posizione, bensì quella del suo primo byte (ossia l’indirizzo del record logico) ed eventualmente la sua lunghezza in byte.
In definitiva potremmo dire che la scelta più conveniente sarebbe quella di utilizzare file strutturati con record a lunghezza costante, perché in grado di fornirci sicuramente un accesso ai dati più efficiente (ammesso che la memoria di massa sia ad accesso diretto). Certo anch'essa presenta alcuni svantaggi: per esempio non sempre è facile stimare a priori la dimensione fissata da dare a ciascun campo e, nella maggior parte dei casi, l'informazione che deve essere memorizzata all'interno di un campo, occupa meno spazio di quello fissato, con inutile spreco di spazio sulle memorie di massa. Ma questi svantaggi sono ampiamente ripagati dalla facilità con cui diventa possibile reperire le informazioni all’interno del file.
Domande da interrogazione
- Che cosa rappresenta un file in Informatica?
- Qual è la differenza tra record fisici e record logici?
- Come influisce il formato file sulla lettura dei dati?
- Quali sono le operazioni fisiche fondamentali sui file?
- Come può un programmatore organizzare logicamente un file?
In Informatica, un file è una sequenza di byte residente su una memoria secondaria di un elaboratore, utilizzata per memorizzare dati in modo permanente.
I record fisici sono unità di trasferimento di dimensione fissa tra memoria di massa e centrale, mentre i record logici sono unità di trasferimento variabili tra applicazioni e file.
Il formato file determina la codifica dei byte, permettendo ai programmi di interpretare correttamente i dati durante la lettura, come avviene con i codici ASCII e UNICODE per i file di testo.
Le operazioni fisiche fondamentali sui file includono creazione, apertura, lettura (input), scrittura (output) e chiusura.
Un programmatore può organizzare un file come una sequenza di record logici, scegliendo tra lunghezza costante o variabile per i record, influenzando così le modalità di accesso e gestione dei dati.