C Tutorial di programmazione sulla gestione dei file ad accesso casuale

Oltre alla più semplice delle applicazioni, la maggior parte dei programmi deve leggere o scrivere file. Potrebbe essere solo per leggere un file di configurazione, un parser di testo o qualcosa di più sofisticato. Questo tutorial si concentra sull'uso di file ad accesso casuale in C.

Programmazione dell'I / O del file ad accesso casuale in C

file binario
D3Damon / Getty Images

Le operazioni di base sui file sono:

  • fopen - apri un file - specifica come viene aperto (lettura / scrittura) e digita (binario / testo)
  • fclose - chiude un file aperto
  • fread: leggi da un file
  • fwrite - scrive su un file
  • fseek / fsetpos - sposta il puntatore di un file da qualche parte in un file
  • ftell / fgetpos - indica dove si trova il puntatore del file

I due tipi di file fondamentali sono text e binario. Di questi due, i file binari sono generalmente più semplici da gestire. Per questo motivo e per il fatto che l'accesso casuale a un file di testo non è qualcosa che devi fare spesso, questo tutorial è limitato ai file binari. Le prime quattro operazioni sopra elencate sono sia per i file di testo che per i file ad accesso casuale. Gli ultimi due solo per l'accesso casuale.

instagram viewer

Accesso casuale significa che è possibile spostarsi in qualsiasi parte di un file e leggere o scrivere dati da esso senza dover leggere l'intero file. Anni fa, i dati venivano archiviati su grandi bobine di nastro per computer. L'unico modo per arrivare a un punto del nastro era leggere tutto il nastro. Poi sono arrivati ​​i dischi e ora puoi leggere direttamente qualsiasi parte di un file.

Programmazione con file binari

Un file binario è un file di qualsiasi lunghezza che contiene byte con valori nell'intervallo da 0 a 255. Questi byte non hanno altro significato a differenza di un file di testo in cui un valore di 13 indica il ritorno a capo, 10 indica l'avanzamento di riga e 26 indica la fine del file. Il software che legge i file di testo ha a che fare con questi altri significati.

I file binari sono un flusso di byte e i linguaggi moderni tendono a lavorare con flussi anziché con file. La parte importante è il flusso di dati anziché da dove proviene. Nel C, puoi pensare ai dati come file o stream. Con accesso casuale, puoi leggere o scrivere in qualsiasi parte del file o del flusso. Con l'accesso sequenziale, è necessario scorrere il file o lo streaming dall'inizio come un nastro grande.

Questo esempio di codice mostra un semplice file binario che viene aperto per la scrittura, con una stringa di testo (char *) che viene scritta in esso. Normalmente lo vedi con un file di testo, ma puoi scrivere del testo in un file binario.

Questo esempio apre un file binario per la scrittura e quindi scrive un carattere * (stringa) in esso. La variabile FILE * viene restituita dalla chiamata fopen (). In caso contrario (il file potrebbe esistere ed essere aperto o di sola lettura o potrebbe esserci un errore con il nome file), restituisce 0.

Il comando fopen () tenta di aprire il file specificato. In questo caso, è test.txt nella stessa cartella dell'applicazione. Se il file include un percorso, tutte le barre rovesciate devono essere raddoppiate. "c: \ folder \ test.txt" non è corretto; devi usare "c: \\ cartella \\ test.txt".

Poiché la modalità file è "wb", questo codice sta scrivendo in un file binario. Il file viene creato se non esiste e, in caso affermativo, viene eliminato qualsiasi cosa contenesse. Se la chiamata a fopen fallisce, forse perché il file era aperto o il nome contiene caratteri non validi o un percorso non valido, fopen restituisce il valore 0.

Sebbene sia possibile verificare che ft sia diverso da zero (esito positivo), questo esempio ha una funzione FileSuccess () per farlo esplicitamente. Su Windows, genera l'esito positivo / negativo della chiamata e il nome file. È un po 'oneroso se si è dopo le prestazioni, quindi è possibile limitare questo al debug. Su Windows, c'è un piccolo overhead che invia testo al debugger di sistema.

Le chiamate fwrite () generano il testo specificato. Il secondo e il terzo parametro sono la dimensione dei caratteri e la lunghezza della stringa. Entrambi sono definiti come size_t che è intero senza segno. Il risultato di questa chiamata è scrivere elementi di conteggio delle dimensioni specificate. Nota che con i file binari, anche se stai scrivendo una stringa (char *), non aggiunge caratteri di ritorno a capo o di avanzamento riga. Se vuoi quelli, devi includerli esplicitamente nella stringa.

Modalità file per la lettura e la scrittura di file

Quando si apre un file, si specifica come deve essere aperto: se crearlo da nuovo o sovrascriverlo e se si tratta di testo o binario, leggere o scrivere e se si desidera accodarlo. Questo viene fatto usando uno o più identificatori di modalità file che sono singole lettere "r", "b", "w", "a" e "+" in combinazione con le altre lettere.

  • r - Apre il file per la lettura. Ciò non riesce se il file non esiste o non può essere trovato.
  • w - Apre il file come file vuoto per la scrittura. Se il file esiste, il suo contenuto viene distrutto.
  • a - Apre il file per la scrittura alla fine del file (aggiungendolo) senza rimuovere il marcatore EOF prima di scrivere nuovi dati nel file; questo crea prima il file se non esiste.

L'aggiunta di "+" alla modalità file crea tre nuove modalità:

  • r + - Apre il file sia in lettura che in scrittura. (Il file deve esistere.)
  • w + - Apre il file come file vuoto sia per la lettura che per la scrittura. Se il file esiste, il suo contenuto viene distrutto.
  • a + - Apre il file per la lettura e l'aggiunta; l'operazione di aggiunta include la rimozione del marker EOF prima che i nuovi dati vengano scritti nel file e il marker EOF venga ripristinato al termine della scrittura. Crea prima il file se non esiste. Apre il file per la lettura e l'aggiunta; l'operazione di aggiunta include la rimozione del marker EOF prima che i nuovi dati vengano scritti nel file e il marker EOF venga ripristinato al termine della scrittura. Crea prima il file se non esiste.

Combinazioni modalità file

Questa tabella mostra le combinazioni di modalità file per file di testo e binari. In genere, leggi o scrivi su un file di testo, ma non entrambi contemporaneamente. Con un file binario, puoi sia leggere che scrivere nello stesso file. La tabella seguente mostra cosa puoi fare con ogni combinazione.

  • r text - leggi
  • rb + binary - leggi
  • r + testo - leggi, scrivi
  • binario r + b: leggi, scrivi
  • rb + binary - leggi, scrivi
  • w text: scrivi, crea, tronca
  • binario wb: scrivere, creare, troncare
  • w + testo: leggi, scrivi, crea, tronca
  • binario w + b: leggi, scrivi, crea, tronca
  • wb + binario: leggi, scrivi, crea, tronca
  • un testo: scrivi, crea
  • binario ab: scrivi, crea
  • a + testo: leggi, scrivi, crea
  • a + b binary: scrivi, crea
  • ab + binario: scrivi, crea

A meno che tu non stia solo creando un file (usa "wb") o ne legga solo uno (usa "rb"), puoi cavartela usando "w + b".

Alcune implementazioni consentono anche altre lettere. Microsoft, ad esempio, consente:

  • t - modalità testo
  • c - commit
  • n - non commit
  • S: ottimizzazione della memorizzazione nella cache per l'accesso sequenziale
  • R - memorizzazione nella cache non sequenziale (accesso casuale)
  • T - temporaneo
  • D - elimina / temporaneo, che uccide il file quando è chiuso.

Questi non sono portatili, quindi usali a tuo rischio e pericolo.

Esempio di archiviazione file ad accesso casuale

Il motivo principale per l'utilizzo dei file binari è la flessibilità che consente di leggere o scrivere in qualsiasi punto del file. I file di testo consentono solo di leggere o scrivere in sequenza. Con la prevalenza di database economici o gratuiti come SQLite e MySQL, riduce la necessità di utilizzare l'accesso casuale ai file binari. Tuttavia, l'accesso casuale ai record dei file è un po 'vecchio stile ma ancora utile.

Esaminando un esempio

Supponiamo che l'esempio mostri una coppia di file di dati e di indice che memorizza le stringhe in un file ad accesso casuale. Le stringhe hanno lunghezze diverse e sono indicizzate dalla posizione 0, 1 e così via.

Esistono due funzioni vuote: CreateFiles () e ShowRecord (int recnum). CreateFiles utilizza un buffer char * di dimensioni 1100 per contenere una stringa temporanea composta dalla stringa di formato msg seguita da n asterischi in cui n varia da 5 a 1004. Due FILE * vengono creati entrambi utilizzando la modalità file wb nelle variabili ftindex e ftdata. Dopo la creazione, vengono utilizzati per manipolare i file. I due file sono

  • index.dat
  • data.dat

Il file indice contiene 1000 record di tipo tipo indice; questo è il tipo di indice struct, che ha i due membri pos (di tipo fpos_t) e size. La prima parte del ciclo:

popola la stringa msg in questo modo.

e così via. Poi questo:

popola la struttura con la lunghezza della stringa e il punto nel file di dati in cui verrà scritta la stringa.

A questo punto, sia la struttura del file di indice che la stringa del file di dati possono essere scritte nei rispettivi file. Sebbene si tratti di file binari, sono scritti in sequenza. In teoria, potresti scrivere record in una posizione oltre l'attuale fine del file, ma non è una buona tecnica da usare e probabilmente non è affatto portatile.

La parte finale è chiudere entrambi i file. Ciò garantisce che l'ultima parte del file sia scritta su disco. Durante le scritture di file, molte delle scritture non vanno direttamente sul disco ma sono contenute in buffer di dimensioni fisse. Dopo che una scrittura riempie il buffer, l'intero contenuto del buffer viene scritto sul disco.

Una funzione di scarico del file forza il flush e puoi anche specificare le strategie di flush del file, ma quelle sono pensate per i file di testo.

Funzione ShowRecord

Per verificare che qualsiasi record specificato dal file di dati possa essere recuperato, è necessario sapere due cose: dove inizia nel file di dati e quanto è grande.

Questo è ciò che fa il file indice. La funzione ShowRecord apre entrambi i file, cerca nel punto appropriato (recnum * sizeof (tipo di indice) e recupera un numero di byte = sizeof (indice).

SEEK_SET è una costante che specifica da dove viene eseguita fseek. Ci sono altre due costanti definite per questo.

  • SEEK_CUR - cerca in relazione alla posizione corrente
  • SEEK_END: ​​cerca l'assoluto dalla fine del file
  • SEEK_SET: cerca l'assoluto dall'inizio del file

È possibile utilizzare SEEK_CUR per spostare il puntatore del file in avanti di sizeof (indice).

Dopo aver ottenuto le dimensioni e la posizione dei dati, non resta che recuperarli.

Qui, usa fsetpos () a causa del tipo di index.pos che è fpos_t. Un modo alternativo è usare ftell invece di fgetpos e fsek invece di fgetpos. La coppia fseek e ftell funzionano con int mentre fgetpos e fsetpos usano fpos_t.

Dopo aver letto il record in memoria, viene aggiunto un carattere null \ 0 per trasformarlo in un vero e proprio c-stringa. Non dimenticarlo o avrai un incidente. Come prima, fclose viene chiamato su entrambi i file. Sebbene non perderai alcun dato se dimentichi fclose (diversamente dalle scritture), avrai una perdita di memoria.

instagram story viewer