Come configurare smartphone e PC. Portale informativo
  • casa
  • Ferro da stiro
  • La programmazione funziona con file di testo. Lavorare con file di testo

La programmazione funziona con file di testo. Lavorare con file di testo

Per il programmatore, un file aperto è rappresentato come una sequenza di dati da leggere o scrivere. Quando un file viene aperto, viene associato a I/O stream ... Le informazioni di output vengono scritte nel flusso, le informazioni di input vengono lette dal flusso.

Quando uno stream viene aperto per I/O, si associa ad una struttura standard di tipo FILE, definita in stdio.h. La struttura FILE contiene le informazioni necessarie sul file.

Il file viene aperto utilizzando la funzione fopen(), che restituisce un puntatore a una struttura FILE, che può essere utilizzata per operazioni successive con il file.

FILE * fopen (nome, tipo);

nome - il nome del file da aprire (compreso il percorso),
type è un puntatore a una stringa di caratteri che determina come accedere al file:

· "R" - apre un file per la lettura (il file deve esistere);

· "W" - apre un file vuoto per la scrittura; se il file esiste, il suo contenuto viene perso;

· "A" - apre il file per la scrittura fino alla fine (per l'aggiunta); il file viene creato se non esiste;

· "R +" - apre un file in lettura e scrittura (il file deve esistere);

· "W +" - apre un file vuoto per la lettura e la scrittura; se il file esiste, il suo contenuto viene perso;

· "A +" - apre il file per la lettura e l'aggiunta, se il file non esiste, viene creato.

Il valore restituito è un puntatore al flusso aperto. Se si verifica un errore, viene restituito NULL.

La funzione fclose() chiude il flusso o gli stream associati ai file aperti con fopen(). Il flusso da chiudere è determinato dall'argomento della funzione fclose().

Valore restituito: valore 0, se lo stream è stato chiuso con successo; EOF costante se si è verificato un errore.

#includere
intero principale ()

nome carattere = "mio.txt";

if (fp = fopen (nome, "r")! = NULL)

// era possibile aprire il file?
... // azioni richieste sui dati

else printf ("Impossibile aprire il file");

Leggere un carattere da un file:

char fgetc (flusso);

L'argomento della funzione è un puntatore a un flusso di tipo FILE. La funzione restituisce il codice del carattere letto. Se viene raggiunta la fine del file o si verifica un errore, viene restituita la costante EOF.
Scrivere un carattere in un file:

fputc (carattere, flusso);

Gli argomenti della funzione sono un carattere e un puntatore a un flusso di tipo FILE. La funzione restituisce il codice del carattere letto.

Le funzioni fscanf() e fprintf() sono simili alle funzioni scanf() e printf(), ma funzionano con file di dati e prendono un puntatore a file come primo argomento.

fscanf (stream, "Input Format", argomenti);
fprintf (stream, "Formato di output", argomenti);

Le funzioni fgets() e fputs() sono destinate all'input/output delle stringhe; sono analoghe alle funzioni gets() e puts() per lavorare con i file.

fgets (puntatore per riga, numero di caratteri, flusso);

I caratteri vengono letti dal flusso fino a quando non viene letto un carattere di nuova riga "\ n", che è incluso nella stringa, o fino alla fine del flusso EOF o fino a quando non è stato letto il numero massimo di caratteri. Il risultato viene inserito in un puntatore a una stringa e terminato con un carattere null "\ 0". La funzione restituisce l'indirizzo della stringa.

fputs (puntatore a stringa, flusso);

Copia una stringa nel flusso dalla posizione corrente. Il carattere nullo di terminazione non viene copiato.
Esempio Inserisci il numero e salvalo nel file s1.txt. Leggi il numero dal file s1.txt, aumentalo di 3 e salvalo nel file s2.txt.

La funzione fopen() apre un flusso per l'uso, associa un file al flusso specificato e quindi restituisce un puntatore FILE al flusso specificato. Molto spesso, un file viene visualizzato come un file su disco. La funzione fopen() ha il seguente prototipo:

FILE * fopen (const char * nomefile, const char * modalità);

Dove mode indica una stringa contenente la modalità desiderata per l'apertura del file. I valori validi per la modalità in Borland C ++ sono mostrati nella tabella. nomefile deve essere una stringa di caratteri che fornisce un nome file valido al sistema operativo e può contenere un percorso.

La funzione fopen() restituisce un puntatore del tipo base FILE. Questo puntatore identifica il file ed è utilizzato dalla maggior parte delle funzioni nel file system. Non dovresti mai cambiarlo da solo. La funzione restituisce un puntatore nullo se il file non può essere aperto.

Come mostra la tabella, il file può essere aperto in modalità testo o binaria. In modalità testo, quando si digita, la sequenza di ritorno a capo e di avanzamento riga viene tradotta in un carattere di nuova riga. Nell'output è vero il contrario: il carattere di nuova riga viene tradotto in ritorno a capo e avanzamento riga. Nessuna traduzione di questo tipo si verifica nei file binari. Quando né t né b sono specificati nell'argomento mode, lo stato del file di testo/binario è determinato dal valore della variabile globale _fmode definita in Borland C++. Per impostazione predefinita, fmode è impostato su O_TEXT, ovvero è impostata la modalità testo. Se imposti _fmode su O_BINARY, i file si apriranno in modalità binaria. (Queste macro sono definite in fcntl.h.) Naturalmente, l'uso di un esplicito t o b rimuove gli effetti associati alla variabile _fmode. Inoltre, _fmode è specifico per i prodotti Borland. Non è definito in ANSI C I/O.

Se hai bisogno di aprire un file chiamato test per la scrittura, dovresti scrivere:

Fp = fopen ("test", "w");

Dove fp è una variabile di tipo FILE *. Tuttavia, di solito puoi vedere quanto segue:

If ((fp = fopen ("test", "w")) == NULL) (
puts ("Impossibile aprire il file.");
uscita (1);
}

Questo metodo consente di rilevare errori durante l'apertura di un file, ad esempio la presenza di protezione da scrittura o mancanza di spazio libero su disco.

Se fopen() viene utilizzato per aprire un file per la scrittura, qualsiasi file preesistente con il nome specificato verrà eliminato. Se un file con il nome specificato non esiste, verrà creato.

Se è necessario aggiungere informazioni alla fine del file, è necessario utilizzare la modalità a (append). Se il file non esiste, verrà creato.

L'apertura di un file per la lettura richiede che il file esista. Se il file non esiste, verrà restituito un errore. Se il file è aperto per l'operazione di lettura/scrittura, non viene eliminato, se presente, e se il file non esiste, viene creato.

Tabella: valori di modalità consentiti

Significato

Apre un file per la lettura. (Si apre come file di testo per impostazione predefinita.)

Crea un file per la scrittura. (Si apre come file di testo per impostazione predefinita.)

Si allega a un file. (Si apre come file di testo per impostazione predefinita.)

Apre un file binario per la lettura.

Apre un file binario per la scrittura.

Aggiungi a un file binario.

Apre un file per la lettura/scrittura. (Si apre come file di testo per impostazione predefinita.)

Crea un file di lettura/scrittura. (Si apre come file di testo per impostazione predefinita.)

Allega o crea un file di lettura/scrittura. (Si apre come file di testo per impostazione predefinita.)

Apre un file binario per la lettura/scrittura.

Crea un file binario di lettura/scrittura.

Allega o crea un binario di lettura/scrittura.

Crea un file di testo per la scrittura.

Si allega a un file di testo.

Apre un file di testo per la lettura.

Crea un file di testo di lettura/scrittura.

Apre o crea un file di testo di lettura/scrittura.

Lavorare con file di testo in C++.

Esistono due tipi principali di file: testo e binario. I file consentono all'utente di leggere grandi quantità di dati direttamente dal disco senza digitarli dalla tastiera.

    Testo vengono chiamati file costituiti da qualsiasi carattere. Sono organizzati in righe, ognuna delle quali termina con un carattere di fine riga. La fine del file stesso è indicata dal simbolo "fine file". Quando si scrivono informazioni in un file di testo, che può essere visualizzato utilizzando qualsiasi editor di testo, tutti i dati vengono convertiti in un tipo di carattere e archiviati in forma di carattere.

    V binario file, le informazioni vengono lette e scritte sotto forma di blocchi di una certa dimensione, in cui possono essere memorizzati dati di qualsiasi tipo e struttura.

Per lavorare con i file, speciale tipi di dati chiamato flussi... Flusso ifstream serve per lavorare con i file in modalità lettura, e ofstream in modalità di registrazione. Per lavorare con i file sia in modalità di scrittura che di lettura, usa lo stream fstream.

Nei programmi C++, quando si lavora con file di testo, è necessario includere le librerie iostream e fstream.

Per scrivi dati in un file di testo, è necessario:

    descrivere una variabile di tipo ofstream.

    informazioni di output su un file.

    assicurati di chiudere il file.

Per letture dati da un file di testo, è necessario:

    descrivere una variabile di tipo ifstream.

    apri il file usando la funzione apri.

    chiudere il file.

Registrazione informazioni in un file di testo

    Come accennato in precedenza, per iniziare a lavorare con un file di testo, è necessario dichiarare una variabile del tipo ofstream. Ad esempio, in questo modo:

    Verrà creata una variabile F per scrivere le informazioni nel file.

    Il passaggio successivo consiste nell'aprire il file per la scrittura. In generale, l'operatore di apertura del flusso sarà simile a questo:

F.open ("file", modalità);

Qui F è una variabile, descritta come ofstream,

file - nome completo del file su disco,

mode - modalità di funzionamento con il file in fase di apertura.

Si prega di notare che è necessario utilizzare una doppia barra quando si specifica il nome completo del file. Ad esempio, il nome completo del file noobs.txt che si trova nella cartella del gioco sull'unità D: dovrebbe essere scritto in questo modo:

D: \\ gioco \\ noobs.txt.

Il file può essere aperto in una delle seguenti modalità:

ios :: in - apre un file in modalità lettura dati, questa modalità è la modalità predefinita per i flussi ifstream;

ios :: out - apre un file nella modalità di registrazione dei dati (le informazioni sul file esistente vengono distrutte), questa modalità è la modalità predefinita per i flussi ofstream;

ios :: app - apre un file nella modalità di scrittura dei dati alla fine del file;

ios :: ate - si sposta alla fine di un file già aperto;

ios :: trunc - cancella il file, lo stesso accade in modalità ios :: out;

ios :: nocreate - non apre il file se non esiste;

ios :: noreplace - non apre un file esistente.

Il parametro mode può essere assente, in questo caso il file viene aperto nella modalità predefinita per questo flusso.

Dopo l'apertura riuscita del file (in qualsiasi modalità), la variabile F memorizzerà true, altrimenti false. Questo verificherà la correttezza dell'operazione di apertura del file.

Puoi aprire il file (prendi come esempio il file D: \\ game \\ noobs.txt) in modalità di registrazione in uno dei seguenti modi:

// primo modo

del flusso F;

F.open ("D: \\ gioco \\ noobs.txt", ios :: out);

// secondo modo, ios :: la modalità out è l'impostazione predefinita

// per flussoofstream

del flusso F;

// il terzo modo combina la descrizione della variabile e il tipo stream

// e apri il file in un'unica istruzione

ofstream F ("D: \\ gioco \\ noobs.txt", ios :: out);

Dopo aver aperto il file in modalità di scrittura, verrà creato un file vuoto, nel quale sarà possibile scrivere informazioni.

Se vuoi aprire un file esistente in modalità di pre-scrittura, usa il valore ios :: app come modalità.

Dopo aver aperto un file in modalità di scrittura, è possibile scrivere su di esso allo stesso modo dello schermo, solo al posto del dispositivo di output standardcoutè necessario specificare il nome del file aperto.

Ad esempio, per scrivere la variabile a nel flusso F, l'operatore di output sarà simile al seguente:

Per l'output sequenziale al flusso G delle variabili b, c, d, l'operatore di output diventerà:

G<

Il flusso viene chiuso utilizzando l'operatore:

ESEMPIO:

Crea un file di testo D: \\ game \\ noobs.txt e scrivi n numeri reali al suo interno.

#include "stdafx.h"

#includere

#includere

#includere

usando lo spazio dei nomi std;

intero principale ()

setlocale (LC_ALL, "RUS");

int io, n;

doppia a;

// descrive un flusso per scrivere dati su un file

ofstream F;

//apro il file in modalità di scrittura,

//modalitàios:: fuoriinstallato per impostazione predefinita

f.open ("D: \\ gioco \\ noobs.txt", ios :: out);

// inserisci il numero di numeri reali

cout<<" n="; cin>> n;

// loop per inserire numeri reali

// e scrivili in un file

per (i = 0; i

cout<<"a=";

// inserisci un numero

cin >> a;

F<

// chiudi il flusso

f.chiudi ();

sistema ("pausa");

restituisce 0;

_______________________________________________________________

Per leggere le informazioni da un file di testo, devi dichiarare una variabile del tipo ifstream... Successivamente, è necessario aprire il file per la lettura utilizzando l'operatore aprire... Se la variabile si chiama F, i primi due operatori saranno così:

F.open ("D: \\ gioco \\ noobs.txt", ios :: in);

Dopo aver aperto un file in modalità di lettura, è possibile leggere le informazioni da esso allo stesso modo della tastiera, solo invece dicinspecificare il nome del flusso da cui verranno letti i dati.

Ad esempio, per leggere dal flusso F nella variabile a, l'istruzione di input sarebbe simile a questa:

Due numeri in un editor di testo sono considerati separati se c'è almeno uno dei caratteri tra di loro: spazio, tabulazione, carattere di fine riga. È bene che il programmatore sappia in anticipo quanti e quali valori sono memorizzati in un file di testo. Tuttavia, il tipo di valori memorizzati nel file è spesso semplicemente noto e il loro numero può variare. Quando si risolve questo problema, è necessario leggere i valori dal file uno alla volta e, prima di ogni lettura, verificare se è stata raggiunta la fine del file. Per questo c'è una funzione F. eof().

Qui F è il nome del flusso La funzione restituisce un valore booleano: vero o falso, a seconda che sia stata raggiunta la fine del file. Pertanto, il ciclo per leggere il contenuto dell'intero file può essere scritto in questo modo:

// predisporre per leggere i valori da un file, eseguire

// il ciclo si interromperà quando raggiungeremo la fine del file,

// in questo caso F.eof() restituirà true

mentre (! F.eof ())

ESEMPIO:

I numeri reali sono memorizzati nel file di testo D: \\ game \\ noobs.txt, visualizzali sullo schermo e calcola il loro numero.

#include "stdafx.h"

#includere

#includere

#includere

#includere

usando lo spazio dei nomi std;

intero principale ()

setlocale (LC_ALL, "RUS");

intn = 0;

galleggiante a;

fstream F;

// apre il file in modalità lettura

F.open ("D: \\ gioco \\ noobs.txt");

// se il file è stato aperto correttamente, allora

// loop per leggere valori da un file; l'esecuzione del ciclo verrà interrotta,

// quando raggiungiamo la fine del file, in questo caso F.eof() restituirà true.

mentre (! F.eof ())

// legge il valore successivo dal flusso F nella variabile a

F >> a;

// mostra il valore della variabile a sullo schermo

cout<

// aumenta il numero di numeri letti

// chiudi il flusso

F.chiudi ();

// inserisci sullo schermo il numero di numeri letti

cout<<"n="<

// se il file è stato aperto in modo errato, l'output

// messaggi sull'assenza di tale file

altro cout<<" Файл не существует"<

sistema ("pausa");

restituisce 0;

C++. Gestione dei file binari

Quando si scrivono informazioni in un file binario, caratteri e numeri vengono scritti come una sequenza di byte.

Per scrivi dati in un file binario, è necessario:

    descrivere una variabile di file di tipo FAIL * utilizzando l'istruzione FILE * nomefile;. Qui filename è il nome della variabile in cui verrà memorizzato il puntatore del file.

    scrivi le informazioni su un file usando la funzione fwrite

Per leggere b dati da un file binario, è necessario:

    descrivere una variabile di tipo FILE *

    apri file con funzione fopen

    chiudi il file usando la funzione fclose

Funzioni di base necessarie per lavorare con i binari.

Per scoperte file, è prevista la funzione fopen.

FILE * fopen (const * nome file, const char * modalità)

Qui filename è una stringa che memorizza il nome completo del file da aprire, mode è una stringa che definisce la modalità di lavoro con il file; sono possibili i seguenti valori:

"Rb" - apre un file binario in modalità lettura;

"Wb" - crea un file binario per la scrittura; se esiste, il suo contenuto viene cancellato;

"Ab" - crea o apre un file binario da aggiungere alla fine del file;

"Rb +" - apre un file binario esistente in modalità lettura e scrittura;

"Wb +" - apre un file binario in modalità lettura/scrittura, il file esistente viene cancellato;

"Ab +": viene aperto o creato un file binario per correggere le informazioni esistenti e aggiungere nuove informazioni alla fine del file.

La funzione restituisce NULL nella variabile file f se il file non viene aperto correttamente. Dopo aver aperto il file, è disponibile il suo 0° byte, il puntatore del file è uguale a 0, il cui valore viene spostato del numero di byte letti (scritti) man mano che viene letto o scritto. Il valore corrente del puntatore del file è il numero di byte, a partire dal quale avverrà l'operazione di lettura o scrittura.

Per chiusura file, è prevista la funzione fclose

int fclose (FILE * nome file);

Restituisce 0 in caso di chiusura riuscita del file e NULL in caso contrario.

La funzione di rimozione è per cancellare File.

int remove (const char * nomefile);

Questa funzione rimuove un file chiamato filenema dal disco. Il file da eliminare deve essere chiuso. La funzione restituisce un valore diverso da zero se non è stato possibile eliminare il file.

Per rinominare file, la funzione di ridenominazione è intesa:

int rename (const char * oldfilename, const char * newfilename);

Il primo parametro è il vecchio nome del file, il secondo è quello nuovo. Restituisce 0 in caso di successo.

Lettura da un file binario viene eseguito utilizzando la funzione fread:

fread (void * ptr, size, n, FILE * nomefile);

La funzione fread legge n elementi di dimensione size dal file filename in un array ptr. La funzione restituisce il numero di elementi letti. Dopo aver letto dal file, il suo puntatore viene spostato di n * byte di dimensione.

Registrazione su un file binario viene eseguito utilizzando la funzione fwrite:

fwrite (const void * ptr, size, n, FILE * nomefile);

La funzione fwrite scrive n elementi di dimensione size nel file filename dall'array ptr. La funzione restituisce il numero di elementi scritti. Dopo aver scritto le informazioni nel file, il puntatore viene spostato di n * byte di dimensione.

Per controllo di fine file esiste una funzione feof:

int feof (FILE * nomefile);

Restituisce un valore diverso da zero se è stata raggiunta la fine del file.

ESEMPIO:

Crea un file binario D: \\ game \\ noobs.dat e scrivici un intero n e n numeri reali.

#include "stdafx.h"

#includere

usando lo spazio dei nomi std;

intero principale ()

setlocale (LC_ALL, "RUS");

int n, io;

doppia a;

// crea un file binario in modalità di scrittura

f = fopen ("D: \\ gioco \\ noobs.dat", "wb");

// ingresso i numerin

cout<<"n="; cin>> n;

fwrite (& n, sizeof (int), 1, f);

// loop per inserire n numeri reali

per (i = 0; i

// input del prossimo numero reale

cout<<"a=";

cin >> a;

// scrive un numero reale in un file binario

fwrite (& a, sizeof (doppio), 1, f);

// chiudere file

fchiudi (f);

sistema ("pausa");

restituisce 0;

ESEMPIO:

Visualizza il contenuto del file binario D: \\ game \\ noobs.dat creato nell'attività precedente

#include "stdafx.h"

#includere

usando lo spazio dei nomi std;

intero principale ()

setlocale (LC_ALL, "RUS");

int n, io;

doppio * a;

FILE * f; // descrivi la variabile del file

// apre un file binario esistente in modalità lettura

// legge dal file un intero nella variabile n

// mostra n sullo schermo

cout<<"n="<

// allocazione della memoria per un array di n numeri

a = nuovo doppio [n];

// legge n numeri reali dal file nell'array a

// mostra l'array sullo schermo

per (i = 0; i

cout<

cout<

// chiudere file

fchiudi (f);

sistema ("pausa");

restituisce 0;

File binario- struttura dati sequenziale, dopo l'apertura del file è disponibile il primo byte in esso contenuto. È possibile scrivere o leggere dati da un file in sequenza. Diciamo che vuoi contare il quindicesimo numero e poi il primo. Con l'accesso sequenziale, questo può essere fatto nel modo seguente:

int n, io;

doppia a;

FILE * f;

f = fopen ("D: \\ gioco \\ noobs.dat", "rb");

per (i = 0; i<15; i++)

fchiudi (f);

f = fopen ("D: \\ gioco \\ noobs.dat", "rb");

fread (& a, sizeof (doppio), 1, f);

fchiudi (f);

Come puoi vedere, leggere i numeri da un file in questo modo e poi riaprire il file non è il modo più conveniente. È molto più comodo usare la funzione fseek per spostare il puntatore del file su un dato byte.

int fseek (FILE * nomefile, long int offset, int origin);

La funzione imposta il puntatore sulla posizione del file corrente F in base al valore di origine e offset. Il parametro offset è uguale al numero di byte di cui il puntatore del file verrà spostato dall'origine specificata dal parametro origin. Il parametro origin deve essere uno dei seguenti valori di offset come definito nell'intestazione stdio.h:

SEEK_SET - dall'inizio del file;

SEEK_CUR - dalla posizione corrente;

SEEK_END - dalla fine del file.

La funzione restituisce zero se l'operazione ha esito positivo, diverso da zero se si verifica un errore durante l'esecuzione di un offset

La funzione fseek implementa effettivamente l'accesso diretto a qualsiasi valore nel file. Hai solo bisogno di conoscere la posizione (numero di byte) del valore nel file. Diamo un'occhiata all'uso dell'accesso diretto nei binari usando l'esempio della risoluzione del problema seguente.

ESEMPIO

Nel file binario precedentemente generato D: \\ game \\ noobs.dat, scambia i numeri reali più grandi e più piccoli.

L'algoritmo per risolvere il problema consiste nelle seguenti fasi:

    leggendo quelli reali da file in array a.

    cerca nell'array a i valori massimo (max) e minimo (min) e i loro numeri (imax, imin).

    sposta il puntatore del file sul valore massimo e scrivi min.

    sposta il puntatore del file sul valore minimo e scrivi max.

Di seguito è riportato il testo del programma per la risoluzione del problema con commenti.

#include "stdafx.h"

#includere

usando lo spazio dei nomi std;

intero principale ()

setlocale (LC_ALL, "RUS");

int n, io, imax, imin;

doppio * a, max, min;

FILE * f;

// apre il file in modalità lettura e scrittura

f = fopen ("D: \\ gioco \\ noobs.dat", "rb +");

// legge l'importo dal file nella variabile n

// numeri reali nel file

fread (& n, sizeof (int), 1, f);

cout<<"n="<

// alloca memoria per memorizzare numeri reali,

// che verrà memorizzato nell'array a

a = nuovo doppio [n];

// legge da file in array e numeri reali

fread (a, sizeof (doppio), n, f);

// trova gli elementi massimo e minimo

// nell'array a e nei loro indici

per (imax = imin = 0, max = min = a, i = 1; i

se (un [i]> max)

massimo = un [i];

se (un [i]

min = un [i];

// in movimento puntatore Per massimo elemento

fseek (f, sizeof (int) + imax * sizeof (doppio), SEEK_SET);

// scrivi min invece dell'elemento di file massimo

fwrite (& min, sizeof (doppio), 1, f);

// in movimento puntatore Per minimo elemento

fseek (f, sizeof (int) + imin * sizeof (doppio), SEEK_SET);

// scrivi max invece dell'elemento file minimo

fwrite (& max, sizeof (doppio), 1, f);

//chiudi il file

fchiudi (f);

// memoria libera

Elimina [ ] un;

sistema ("pausa");

Per facilità di riferimento, le informazioni nei dispositivi di archiviazione sono archiviate sotto forma di file.

Il file è un'area denominata della memoria esterna allocata per la memorizzazione di una matrice di dati. I dati contenuti nei file sono della natura più varia: programmi in linguaggio algoritmico o macchina; dati iniziali per il funzionamento dei programmi oi risultati dell'esecuzione dei programmi; testi arbitrari; grafica, ecc.

Directory (cartella, directory) - una raccolta denominata di byte su un supporto di memorizzazione, contenente il nome di sottodirectory e file, viene utilizzata nel file system per semplificare l'organizzazione dei file.

File systemè la parte funzionale del sistema operativo che fornisce operazioni sui file. Esempi di file system sono FAT (FAT - File Allocation Table), NTFS, UDF (usato sui CD).

Esistono tre versioni principali di FAT: FAT12, FAT16 e FAT32. Differiscono nella profondità di bit dei record nella struttura del disco, ad es. il numero di bit allocati per memorizzare il numero di cluster. FAT12 viene utilizzato principalmente per floppy disk (fino a 4 KB), FAT16 per piccoli dischi, FAT32 per unità FLASH ad alta capacità (fino a 32 GB).

Diamo un'occhiata alla struttura del file system usando FAT32 come esempio.

Struttura file FAT32

I dispositivi di memoria esterni nel sistema FAT32 non hanno byte, ma indirizzano i blocchi. Le informazioni vengono scritte sul dispositivo di memoria esterno in blocchi o settori.

Un settore è la più piccola unità indirizzabile di archiviazione delle informazioni su dispositivi di archiviazione esterni. In genere, la dimensione del settore è fissata a 512 byte. Per aumentare lo spazio degli indirizzi dei dispositivi di memoria esterni, i settori vengono combinati in gruppi chiamati cluster.

Un cluster è un'unione di più settori, che può essere considerato come un'unità indipendente con determinate proprietà. La proprietà principale di un cluster è la sua dimensione, misurata in numero di settori o numero di byte.

Il file system FAT32 ha la seguente struttura.

I cluster utilizzati per la registrazione dei file sono numerati a partire da 2. Di norma, il cluster n. 2 viene utilizzato dalla directory principale e, a partire dal cluster n. 3, viene archiviato un array di dati. I settori utilizzati per memorizzare le informazioni presentate sopra la directory principale non sono raggruppati.
La dimensione minima del file su disco è 1 cluster.

Il settore di avvio inizia con le seguenti informazioni:

  • EB 58 90 - filiale incondizionata e firma;
  • 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
  • 00 02 - il numero di byte nel settore (solitamente 512);
  • 1 byte - il numero di settori nel cluster;
  • 2 byte - il numero di settori liberi.

Inoltre, il settore di avvio contiene le seguenti informazioni importanti:

  • 0x10 (1 byte) - numero di tabelle FAT (solitamente 2);
  • 0x20 (4 byte) - il numero di settori sul disco;
  • 0x2С (4 byte) - numero del cluster della directory principale;
  • 0x47 (11 byte) - etichetta del volume;
  • 0x1FE (2 byte) - firma del settore di avvio (55 AA).

Il settore delle informazioni sul filesystem contiene:

  • 0x00 (4 byte) - firma (52 52 61 41);
  • 0x1E4 (4 byte) - firma (72 72 41 61);
  • 0x1E8 (4 byte) - numero di cluster liberi, -1 se non noto;
  • 0x1EC (4 byte) - numero dell'ultimo cluster registrato;
  • 0x1FE (2 byte) - firma (55 AA).

Il FAT contiene informazioni sullo stato di ciascun cluster su disco. I 2 byte inferiori del FAT memorizzano F8 FF FF 0F FF FF FF FF (che corrisponde allo stato dei cluster 0 e 1, che sono fisicamente assenti). Inoltre, lo stato di ogni cluster contiene il numero del cluster in cui continua il file corrente o le seguenti informazioni:

  • 00 00 00 00 - il cluster è libero;
  • FF FF FF 0F - fine del file corrente.
  • 8 byte - nome file;
  • 3 byte - estensione del file;

La directory principale contiene una serie di record di informazioni a 32 bit per ciascun file, contenenti le seguenti informazioni:

Quando si lavora con nomi di file lunghi (compresi i nomi russi), il nome del file è codificato nel sistema di codifica UTF-16. In questo caso vengono allocati 2 byte per la codifica di ciascun carattere. In questo caso, il nome del file è scritto nella forma della seguente struttura:

  • 1 byte di sequenza;
  • 10 byte contengono i 5 caratteri meno significativi del nome del file;
  • attributo 1 byte;
  • 1 byte riservato;
  • 1 byte - checksum del nome DOS;
  • 12 byte contengono i 3 caratteri meno significativi del nome del file;
  • 2 byte - numero del primo cluster;
  • altri caratteri del nome lungo.

Lavorare con file in linguaggio C

Per il programmatore, un file aperto è rappresentato come una sequenza di dati da leggere o scrivere. Quando un file viene aperto, viene associato a I/O stream... Le informazioni di output vengono scritte nel flusso, le informazioni di input vengono lette dal flusso.

Quando uno stream viene aperto per I/O, si associa ad una struttura standard di tipo FILE, definita in stdio.h. La struttura FILE contiene le informazioni necessarie sul file.

Il file viene aperto utilizzando la funzione fopen(), che restituisce un puntatore a una struttura FILE, che può essere utilizzata per operazioni successive con il file.

FILE * fopen (nome, tipo);


nome - il nome del file da aprire (compreso il percorso),
type è un puntatore a una stringa di caratteri che determina come accedere al file:
  • "r" - apre un file per la lettura (il file deve esistere);
  • "w" - apre un file vuoto per la scrittura; se il file esiste, il suo contenuto viene perso;
  • "a" - apre il file per scrivere fino alla fine (per aggiungere); il file viene creato se non esiste;
  • "r +" - apre un file in lettura e scrittura (il file deve esistere);
  • "w +" - apre un file vuoto per la lettura e la scrittura; se il file esiste, il suo contenuto viene perso;
  • "a +" - apre il file per la lettura e l'aggiunta, se il file non esiste, viene creato.

Il valore restituito è un puntatore al flusso aperto. Se si verifica un errore, viene restituito NULL.

La funzione fclose() chiude il flusso o gli stream associati ai file aperti con fopen(). Il flusso da chiudere è determinato dall'argomento della funzione fclose().

Valore restituito: valore 0, se lo stream è stato chiuso con successo; EOF costante se si è verificato un errore.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#includere
intero principale () (
FILE * fp;
nome carattere = "mio.txt";
if ((fp = fopen (nome, "r")) == NULL)
{
printf ( "Impossibile aprire il file");
getchar();
restituisce 0;
}
// apri il file con successo
... // azioni richieste sui dati
fchiudi (fp);
getchar();
restituisce 0;
}

Leggere un carattere da un file:

char fgetc (flusso);


L'argomento della funzione è un puntatore a un flusso di tipo FILE. La funzione restituisce il codice del carattere letto. Se viene raggiunta la fine del file o si verifica un errore, viene restituita la costante EOF.

Scrivere un carattere in un file:

fputc (carattere, flusso);

Gli argomenti della funzione sono un carattere e un puntatore a un flusso di tipo FILE. La funzione restituisce il codice del carattere letto.

Le funzioni fscanf() e fprintf() sono simili alle funzioni scanf() e printf(), ma funzionano con file di dati e prendono un puntatore a file come primo argomento.

fscanf (stream, "Input Format", argomenti);

Il meccanismo di I/O sviluppato non corrisponde allo stile generalmente accettato di programmazione orientata agli oggetti, inoltre, utilizza attivamente operazioni con puntatori, che sono considerati potenzialmente non sicuri nei moderni ambienti di esecuzione di codice protetto. Un'alternativa nello sviluppo di applicazioni applicate è il meccanismo delle classi I/O standard fornito dallo standard del linguaggio C++.

Apertura dei file

Le classi più comunemente usate sono ifstream per la lettura, ofstream per la scrittura e fstream per la modifica dei file.

Tutte le classi di I/O in streaming sono derivate indirettamente dal comune antenato ios, ereditandone interamente le funzionalità. Pertanto, la modalità di apertura dei file è specificata dal membro dati del tipo enumerato open_mode, che è definito come segue:

Enum open_mode (app, binary, in, out, trunc, ate);

Di seguito sono riportati i possibili valori delle bandiere e il loro scopo.

Ad esempio, per aprire un file denominato test.txt per leggere i dati in formato binario, scrivi:

file Ifstream; file.open ("test.txt", ios :: in | ios :: binary);

L'operatore OR logico (|) consente di creare una modalità con qualsiasi combinazione di flag. Affinché, quando si apre un file mediante registrazione, non si sovrascriva accidentalmente un file esistente con lo stesso nome, è necessario utilizzare il seguente modulo:

File ofstream; file.open ("test.txt", ios :: out | ios :: app);

Si presume che il file di intestazione corrispondente sia collegato al progetto:

#includere

Per verificare se il file è stato aperto con successo, puoi usare la costruzione

If (! File) (// Gestire l'errore di apertura del file)

Includere e recuperare operatori

Ignorato nelle classi di gestione dei file operatore di inclusione (<<) записывает данные в файловый поток. Как только вы открыли файл для записи, можно записывать в него текстовую строку целиком:

File<< "Это строка текста";

Puoi anche scrivere la stringa di testo pezzo per pezzo:

File<< "Это " << "строка " << "текста";

L'istruzione endl termina l'input con un ritorno a capo:

File<< "Это строка текста" << endl;

Utilizzando l'operatore include, è facile scrivere i valori delle variabili o degli elementi dell'array in un file:

File ofstream ("Temp.txt"); char buff = "L'array di testo contiene variabili"; int vx = 100; galleggiante pi = 3,14159; file<< buff << endl << vx << endl << pi << endl;

Come risultato dell'esecuzione del codice, vengono formate tre righe del file di testo Temp.txt:

L'array di testo contiene le variabili 100 3.14159

Nota che i valori numerici vengono scritti nel file come stringhe di testo, non come valori binari.

Operatore di estrazione(>>) fa il contrario. Sembrerebbe che per estrarre i simboli dal file Temp.txt registrato in precedenza, sia necessario scrivere un codice come il seguente:

File Ifstream ("Temp.txt"); appassionato di salmerino; int vx; galleggiante pi; file >> buff >> vx >> pi;

Tuttavia, l'operatore di estrazione si fermerà al primo delimitatore (spazio, tabulazione o carattere di nuova riga) che trova. Pertanto, quando si analizza la frase "L'array di testo contiene variabili" solo la parola "Testo" verrà scritta nell'array buff, lo spazio viene ignorato e la parola "array" diventerà il valore della variabile intera vx e il codice l'esecuzione "andrà selvaggia" con un'inevitabile violazione della struttura dei dati. Successivamente, quando discuteremo della classe ifstream, ti mostreremo come organizzare correttamente la lettura del file dall'esempio precedente.

Classe Ifstream: lettura di file

Come suggerisce il nome, la classe ifstream ha lo scopo di inserire un flusso di file. Di seguito sono riportati i principali metodi della classe. La maggior parte di essi è ereditata dalla classe istream e viene sovraccaricata di funzionalità padre estese. Ad esempio, la funzione get, a seconda del parametro call, può leggere non solo un singolo carattere, ma anche un blocco di caratteri.

Ora è chiaro come è necessario modificare l'esempio precedente in modo che l'utilizzo dell'operatore di recupero dati fornisca il risultato atteso:

File Ifstream ("Temp.txt"); appassionato di salmerino; int vx; galleggiante pi; file.getline (buff, sizeof (buff)); file >> vx >> pi:

Il metodo getline leggerà la prima riga del file fino alla fine e l'operatore >> assegnerà valori alle variabili.

L'esempio seguente mostra l'aggiunta di dati a un file di testo e quindi la lettura dell'intero file. Il ciclo while (1) viene utilizzato al posto di while (! File2.eof()) per i motivi discussi in.

#includere #includere usando lo spazio dei nomi std; int main() (ofstream file; file.open ("test.txt", ios :: out | ios :: app); if (! file) (cout<< "File error - can"t open to write data!"; cin.sync(); cin.get(); return 1; } for (int i=0; i<10; i++) file << i << endl; file.close(); ifstream file2; file2.open("test.txt", ios::in); if (!file2) { cout << "File error - can"t open to read data!"; cin.sync(); cin.get(); return 2; } int a,k=0; while (1) { file2 >> un; if (file2.eof()) break; cout<< a << " "; k++; } cout << endl << "K=" << k << endl; file2.close(); cin.sync(); cin.get(); return 0; }

L'esempio seguente mostra un ciclo per leggere le righe dal file test.txt e visualizzarle sulla console.

#includere #includere usando lo spazio dei nomi std; int main() (ifstream file; // crea il file oggetto del flusso file.open ("test.txt"); // apre il file per la lettura if (! file) return 1; // restituisce l'errore di apertura char str; // static line buffer // Legge e visualizza le righe in un ciclo fino a eof while (! file.getline (str, sizeof (str)). eof ()) cout<< str << endl; // вывод прочитанной строки на экран cin.sync(); cin.get(); return 0; }

Questo codice sotto il sistema operativo Windows dipende anche dalla presenza di un carattere di avanzamento riga nell'ultima riga del file, sarebbe più sicuro farlo:

Mentre (1) (if (file.eof ()) break; file.getline (str, sizeof (str)); cout<< str << endl; }

Le chiamate esplicite ai metodi open e close sono facoltative. Infatti, chiamare il costruttore con un argomento consente di aprire immediatamente un file al momento della creazione di un file oggetto di flusso:

File Ifstream ("test.txt");

Invece del metodo close, puoi usare l'operatore delete, che chiamerà automaticamente il distruttore dell'oggetto file e chiuderà il file. Il codice del ciclo while assicura che la fine del file sia controllata correttamente.

La classe ofstream: scrivere file

La classe ofstream è progettata per produrre dati da un flusso di file. Di seguito sono riportati i metodi principali di questa classe.

L'operatore di inclusione descritto in precedenza è utile per organizzare la scrittura in un file di testo:

File ofstream ("temp.txt"); if (! file) ritorna; per (int i = 1; i<=3; i++) file << "Строка " << i << endl; file.close();

File binari

Fondamentalmente, i dati binari vengono serviti come dati di testo. La differenza è che se i dati binari sono scritti in una certa struttura logica, allora devono essere letti dal file in una variabile dello stesso tipo di struttura.

Il primo parametro dei metodi write e read (l'indirizzo del blocco write/read) deve avere il tipo di un carattere puntatore char *, quindi deve essere eseguita una conversione esplicita del tipo di indirizzo della struttura void *. Il secondo parametro specifica che i blocchi binari del file hanno una dimensione in byte costante indipendentemente dalla lunghezza effettiva del record. La seguente appendice fornisce un esempio di come creare e visualizzare i dati per un notebook di base. I record del file vengono quindi letti in sequenza e visualizzati sulla console.

#includere #includere #includere usando lo spazio dei nomi std; struct Notes (// struttura dati del notebook char Name; // nome completo char Phone; // phone int Age; // age); int main () (setlocale (LC_ALL, "Russian"); Note Nota1 = ("Ivan il Terribile", "non installato", 60); Note Nota2 = ("Boris Fedorovich Godunov", "095-111-2233", 30); Note Nota3 = ("Romanov Petr Mikhailovich", "812-333-2211", 20); ofstream ofile ("Notebook.dat", ios :: binary); ofile.write ((char *) & Note1, sizeof (Note)); // 1° blocco ofile.write ((char *) & Note2, sizeof (Notes)); // 2° blocco ofile.write ((char *) & Note3, sizeof (Notes)); / / 3° blocco ofile.close (); // chiude il file registrato ifstream ifile ("Notebook.dat", ios :: binary); Notes Note; // variabile strutturata char str; // buffer di stringa statica // Legge e visualizza le righe in un ciclo fino a eof while (! ifile.read ((char *) & Note, sizeof (Notes)). eof ()) (sprintf (str, "% s \ t Body:% s \ t Age:% d" , Nota.Nome, Nota.Telefono, Nota.Età); cout<< str << endl; } ifile.close(); // закрыть прочитанный файл cin.sync(); cin.get(); return 0; }

Come risultato dell'esecuzione di questo codice, un file binario Notebook.dat è formato da tre blocchi di 80 byte ciascuno (a condizione che i caratteri siano a byte singolo). Naturalmente è possibile utilizzare altri metodi di streaming ed eseguire qualsiasi operazione sui campi di una specifica struttura dati.

Classe Fstream: accesso casuale ai file

Supponiamo che ci siano 100 voci nel nostro taccuino e vogliamo contare il 50°. Naturalmente, puoi organizzare un ciclo e leggere tutti i record dal primo al dato. Ovviamente una soluzione più mirata è impostare il puntatore della posizione del file pos direttamente per registrare 50 e leggerlo:

Ifstream ifile ("Notebook.dat", ios :: binary); int pos = 49 * sizeof (Note); ifile.seekg (pos); // trova la 50a voce Note Nota; // Notes - la struttura "record" di cui sopra ifile.read ((char *) & Note, sizeof (Notes));

Ricerche come queste sono efficaci se il file è costituito da record di dimensioni note e costanti. Per sostituire il contenuto di una voce arbitraria, è necessario aprire il flusso di output in modalità di modifica:

Ofstream ofile ("Notebook.dat", ios :: binary | ios :: ate); int pos = 49 * sizeof (Note); ofile ricerca (pos); // cerca il 50° record Note Note50 = ("Boris Eltsin", "095-222-3322", 64); ofile.write ((char *) & Note, sizeof (Notes)); // sostituzione

Se non specifichi il flag ios :: ate (o ios :: app), quando apri il file binario Notebook.dat, il suo contenuto precedente verrà cancellato!

Infine, è possibile aprire un file contemporaneamente in lettura/scrittura utilizzando metodi ereditati dalla classe stream fstream dai suoi predecessori. Poiché la classe fstream è derivata da istream e ostream (i genitori di ifstream e ofstream, rispettivamente), tutti i metodi precedentemente menzionati sono resi disponibili nell'applicazione.

L'esempio seguente scambia la prima e la terza voce nel file Notebook.dat.

#includere #includere #includere usando lo spazio dei nomi std; struct Note (char Nome; char Telefono; int Età;); int main() (setlocale (LC_ALL, "Russian"); Notes Note1, Note3; // Apri file per leggere/scrivere contemporaneamente file fstream ("Notebook.dat", ios :: binary | ios :: in | ios :: out); file.seekg (2 * sizeof (Notes)); // trova e legge Note3 file.read ((char *) & Note3, sizeof (Notes)); file.seekg (0); // trova e legge Note1 file.read ((char *) & Note1, sizeof (Notes)); file.seekg (0); // Note1<== Note3 file.write((char*)&Note3, sizeof(Notes)); file.seekg(2 * sizeof(Notes)); // Note3 <== Note1 file.write((char*)&Note1, sizeof(Notes)); char str; // Считывать и отображать записи в цикле, пока не eof file.seekg(0); // вернуться к началу файла while (!file.read((char*)&Note1, sizeof(Notes)).eof()) { sprintf(str, "%s\tТел: %s\tВозраст: %d", Note1.Name, Note1.Phone, Note1.Age); cout << str << endl; } file.close(); cin.sync(); cin.get(); return 0; }

I flag ios :: in e ios :: out devono essere specificati nel costruttore dell'oggetto file, consentendo operazioni di lettura e scrittura simultanee. In seguito all'esecuzione di questo codice, vengono scambiati il ​​primo e il terzo record del file binario Notebook.dat.

Ci sono altri esempi sull'argomento.

Principali articoli correlati