Prima di allora, quando i dati I / O, lavoravamo con flussi standard: una tastiera e un monitor. Ora diamo un'occhiata a come il linguaggio C implementa la ricezione di dati dai file e la loro scrittura lì. Prima di eseguire queste operazioni, è necessario aprire il file e accedervi.
Nel linguaggio di programmazione C, un puntatore a file è di tipo FILE e la sua dichiarazione ha questo aspetto:
FILE * miofile;
D'altra parte, la funzione fopen() apre il file all'indirizzo specificato come primo argomento in modalità read ("r"), write ("w") o append ("a") e restituisce un puntatore ad esso nel programma. Pertanto, il processo di apertura di un file e di connessione al programma si presenta così:
miofile = fopen ("ciao.txt", "r");
Quando si leggono o si scrivono dati su un file, è possibile accedervi tramite un puntatore a file (in questo caso, miofile).
Se per qualche motivo (non c'è nessun file all'indirizzo specificato, l'accesso è negato) la funzione fopen() non può aprire il file, allora restituisce NULL. Nei programmi reali, l'errore di apertura di un file nel ramo if viene quasi sempre gestito, ma lo ometteremo ulteriormente.
La dichiarazione della funzione fopen() è contenuta nel file di intestazione stdio.h, quindi deve essere inclusa. Il tipo di struttura FILE è dichiarato anche in stdio.h.
Al termine del lavoro con il file, è consuetudine chiuderlo per liberare il buffer di dati e per altri motivi. Ciò è particolarmente importante se il programma continua a funzionare dopo aver lavorato con il file. L'interruzione della connessione tra un file esterno e un puntatore ad esso dal programma viene eseguita utilizzando la funzione fclose(). Gli viene passato un puntatore a un file come parametro:
fclose (miofile);
È possibile aprire più di un file nel programma. In questo caso, ogni file deve essere associato al proprio puntatore di file. Tuttavia, se il programma funziona prima con un file, quindi lo chiude, è possibile utilizzare il puntatore per aprire il secondo file.
Leggere e scrivere in un file di testo
fscanf()
La funzione fscanf() ha un significato simile alla funzione scanf(), ma a differenza di essa riceve input formattati da un file anziché input standard. La funzione fscanf() accetta parametri: un puntatore a file, una stringa di formato, indirizzi di aree di memoria per la scrittura dei dati:
fscanf (miofile, "% s% d", str, & a);
Restituisce la quantità di dati letti correttamente o EOF. Gli spazi, i caratteri di nuova riga vengono conteggiati come separatori di dati.
Supponiamo di avere un file contenente la seguente descrizione degli oggetti:
Mele 10 23,4 banane 5 25,0 pane 1 10,3
#includere
In questo caso vengono dichiarate una struttura e un array di strutture. Ogni riga del file corrisponde a un elemento dell'array; un elemento array è una struttura contenente una stringa e due campi numerici. Il ciclo legge una riga per iterazione. Quando si incontra la fine del file, fscanf() restituisce EOF e il ciclo termina.
fget ()
La funzione fgets() è simile alla funzione gets() e prende l'input riga per riga da un file. Una chiamata fgets() leggerà una riga. In questo caso, puoi leggere non l'intera riga, ma solo una parte dall'inizio. I parametri Fgets() hanno questo aspetto:
fgets (char_array, numero di caratteri da leggere, puntatore_ al file)
Ad esempio:
fgets (str, 50, miofile)
Tale chiamata di funzione leggerà dal file associato al puntatore myfile un'intera riga di testo se la sua lunghezza è inferiore a 50 caratteri, tenendo conto del carattere "\ n", che la funzione memorizzerà anche nell'array. L'ultimo (50esimo) elemento nell'array str sarà il carattere "\ 0" aggiunto da fgets (). Se la stringa è più lunga, la funzione leggerà 49 caratteri e scriverà "\0" alla fine. In questo caso, "\ n" non sarà contenuto nella riga di lettura.
#includere
In questo programma, a differenza del precedente, i dati vengono letti riga per riga nell'array arr. Quando viene letta la riga successiva, quella precedente viene persa. La funzione fgets() restituisce NULL se non riesce a leggere la riga successiva.
getc() o fgetc()
La funzione getc() o fgetc() (funzionano entrambe) ti permette di ottenere il carattere successivo dal file.
while ((arr [i] = fgetc (file))! = EOF) (if (arr [i] == " \ n ") (arr [i] = " \0 " ; printf ("% s \ n ", arr); io = 0; ) altrimenti io ++; ) arr [i] = " \0 " ; printf ("% s \ n ", arr);
Il codice di esempio visualizza sullo schermo i dati di un file.
Scrivere su un file di testo
Oltre all'input, l'output sul file può essere diverso.
- Uscita formattata. Funzione Fprintf (file_pointer, format_string, variabili).
- Uscita riga per riga. Funzione fputs (stringa, file_pointer).
- Uscita carattere per carattere. Fputc() o putc (char, file_pointer).
Di seguito sono riportati esempi di codice che utilizzano tre modi per inviare i dati a un file.
Scrittura di campi di una struttura su ogni riga del file:
file = fopen ("fprintf.txt", "w"); while (scanf ("% s% u% f", shop [i] .name, & (shop [i] .qty), & (shop [i] .price))! = EOF) (fprintf (file, " % s% u% .2f \ n ", negozio [i] .nome, negozio [i] .qty, negozio [i] .prezzo); io++; )
L'output riga per riga in un file (fputs()), a differenza di puts() stesso non inserisce "\ n" alla fine della riga):
while (ottiene (arr)! = NULL) (fputs (arr, file); fputs (" \ n ", file); )
Un esempio di output carattere per carattere:
while ((i = getchar())! = EOF) putc (i, file);
Leggere e scrivere da un file binario
Puoi lavorare con un file non come una sequenza di caratteri, ma come una sequenza di byte. In linea di principio, è impossibile lavorare in modo diverso con file non di testo. Tuttavia, puoi leggere e scrivere su file di testo in questo modo. Il vantaggio di questa modalità di accesso a un file è la velocità di lettura-scrittura: un accesso può leggere/scrivere un blocco significativo di informazioni.
Quando si apre un file per l'accesso binario, il secondo parametro di fopen() è la stringa "rb" o "wb".
L'argomento del lavoro con i binari è piuttosto complesso e richiede una lezione separata per impararlo. Qui noteremo solo le peculiarità delle funzioni di lettura e scrittura su un file, che è considerato come un flusso di byte.
Le funzioni fread() e fwrite() prendono come parametri:
- l'indirizzo dell'area di memoria da cui vengono scritti o letti i dati,
- la dimensione di un dato tipo,
- la quantità di dati da leggere della dimensione specificata,
- puntatore di file.
Queste funzioni restituiscono il numero di dati letti o scritti con successo. Quelli. puoi "ordinare" la lettura di 50 elementi di dati e ottieni solo 10. Non ci saranno errori.
Un esempio di utilizzo delle funzioni fread() e fwrite():
#includere
Qui si tenta di leggere 50 caratteri dal primo file. N memorizza il numero di caratteri effettivamente letti. N può essere 50 o meno. I dati vengono inseriti in una stringa. La stessa cosa accade con il secondo file. Successivamente, la prima riga viene aggiunta alla seconda e i dati vengono scaricati nel terzo file.
Risolvere problemi
- Scrivere un programma che chieda all'utente il nome (indirizzo) di un file di testo, quindi lo apra e conti il numero di caratteri e righe in esso contenuti.
- Scrivere un programma che scriva dati su un file ricevuto da un altro file e modificato in un modo o nell'altro prima di scrivere. Ogni riga di dati ricevuta da un file deve rientrare in una struttura.
- confronto per identificare l'uguaglianza o la disuguaglianza.
Lo scopo pratico di un'enumerazione è definire un insieme di diverse costanti simboliche di tipo intero.
Un esempio di utilizzo di variabili enumerate:
mo = 1, tu, we, th, fr, sa, su) giorni;
puts ("Inserisci il giorno della settimana (da 1 a 7):"); scanf ("% d", & t_day);
w_day = su; inizio = mese;
fine = w_day -t_day;
printf ("\ n lunedì è% d-esimo giorno della settimana, \ ora% d-esimo giorno. \ n \
Ci sono % d giorni (giorni) fino alla fine della settimana. ”, Inizio, t_day, fine);
Il risultato del programma: Inserire il giorno della settimana (da 1 a 7): 2
Il lunedì è il 1° giorno della settimana, ora il 2° giorno. Fino alla fine della settimana 5 giorni (giorno).
18. File in linguaggio C
Un file è un insieme di dati che si trova su un supporto esterno e considerato nel processo di elaborazione nel suo insieme. I file contengono dati destinati all'archiviazione a lungo termine.
Esistono due tipi di file: di testo e binari. I file di testo sono una sequenza di caratteri ASCII e possono essere visualizzati e modificati con qualsiasi editor di testo.
I file binari (binari) sono una sequenza di dati, la cui struttura è definita a livello di codice.
Il linguaggio C ha un ampio set di funzioni per lavorare con i file, la maggior parte delle quali si trovano nelle librerie stdio.h e io.h.
18.1. Apertura di un file
Ad ogni file viene assegnato un nome logico interno, che viene utilizzato in seguito quando vi si fa riferimento. Il nome logico (ID file) è
un puntatore a un file, ad es. nell'area di memoria, che contiene tutte le informazioni necessarie sul file. Il formato per dichiarare un puntatore a file è il seguente:
FILE * puntatore al file; |
|
FILE è un identificatore di tipo strutturato descritto nella libreria standard |
|
stdio.h e contenente le seguenti informazioni: |
|
tipo struttura ( | |
- il numero di byte non letti rimasti nel buffer; |
|
la normale dimensione del buffer è di 512 byte; non appena livello = 0, |
|
il blocco di dati successivo viene letto nel buffer dal file; |
|
- flag di stato del file - leggi, scrivi, aggiungi; |
|
- descrittore di file, ad es. il numero che definisce il suo no- |
|
char hold senza segno; | - carattere non impegnato, ad es. simbolo ungetc; |
- la dimensione del buffer intermedio interno; |
|
buffer di caratteri senza segno; | - il valore del puntatore a cui accedere all'interno del buffer, es. |
specifica l'inizio del buffer, l'inizio della riga o il valore corrente |
|
lettura del puntatore all'interno del buffer, a seconda della modalità |
|
ma buffering; |
|
unsigned char * curp; | - il valore attuale del puntatore per accedere all'interno del bu- |
fer, cioè imposta la posizione corrente nel buffer per lo scambio |
|
avanti con il programma; |
|
istemp non firmato; | - flag file temporaneo; |
- flag quando si lavora con un file; |
|
) FILE; |
Prima di iniziare a lavorare con il file, ad es. per poter leggere o scrivere informazioni su un file, è necessario aprirlo per l'accesso. Per questo, di solito viene utilizzata la funzione
FILE * fopen (char * nome file, char * modalità);
prende la rappresentazione esterna - il nome fisico del file sul supporto (disco floppy, disco rigido) e gli assegna un nome logico.
Nome fisico, ad es. il nome del file e il suo percorso sono specificati dal primo parametro
- una riga, ad esempio, "a: Mas_dat.dat" - un file denominato Mas_dat.dat situato su un dischetto, "d: \\ work \\ Sved.txt" - un file denominato Sved.txt situato sul disco rigido drive nella directory di lavoro ...
Attenzione! Una barra rovesciata (\), come carattere speciale, viene scritta due volte in una stringa.
Dopo l'apertura riuscita, la funzione fopen restituisce un puntatore a file (di seguito denominato puntatore a file). Restituisce NULL in caso di errore. Questa situazione si verifica in genere quando il percorso del file che si sta aprendo è specificato in modo errato. Ad esempio, se specifichi un percorso in cui è vietato scrivere nell'aula espositiva del nostro ateneo (di solito d:\lavoro\è consentito).
Il secondo parametro è una stringa che imposta la modalità di accesso ai file:
w - il file viene aperto per la scrittura; se non esiste un file con il nome specificato, verrà creato; se tale file esiste, le informazioni precedenti vengono distrutte prima dell'apertura;
r - il file viene aperto in sola lettura; se non esiste tale file, si verifica un errore;
a - il file viene aperto per aggiungere nuove informazioni alla fine;
r + - il file viene aperto per la modifica dei dati - sono possibili sia la scrittura che la lettura delle informazioni;
w + - lo stesso di r +;
a + - lo stesso di a, solo la scrittura può essere eseguita ovunque nel file; è disponibile anche la lettura di file;
t - il file viene aperto in modalità testo; b - il file viene aperto in modalità binaria.
La modalità testo differisce dalla modalità binaria in quanto quando il file viene aperto come una coppia di caratteri di testo "line feed", "carriage return" è sostituito da un carattere: "line feed" per tutte le funzioni di scrittura dei dati sul file, e per tutte le funzioni di output il carattere "avanzamento riga" è ora sostituito da due caratteri: "avanzamento riga", "ritorno a capo".
Per impostazione predefinita, il file si apre in modalità testo. Esempio: FILE * f; - viene dichiarato un puntatore a un file f;
f = fopen ("d: \\ lavoro \\ Dat_sp.cpp", "w"); - viene aperto in scrittura un file con nome logico f con nome fisico Dat_sp.cpp, che si trova sul disco d, nella directory di lavoro; o più brevemente
FILE * f = fopen ("d: \\ lavoro \\ Dat_sp.cpp", "w");
18.2. Chiusura del file
Dopo aver lavorato con il file, l'accesso ad esso deve essere chiuso. Questo viene fatto da int fclose (puntatore al file). Ad esempio, dall'esempio precedente, il file viene chiuso in questo modo: fclose (f);
Per chiudere più file è stata introdotta una funzione che viene dichiarata come segue: void fcloseall (void);
Se è necessario modificare la modalità di accesso per un file, è necessario prima chiudere questo file e quindi riaprirlo, ma con diritti di accesso diversi. Per fare ciò, usa la funzione standard:
FILE * freopen (char * nome_file, char * modalità, FILE * puntatore_file);
Questa funzione chiude prima il file dichiarato file_pointer(come fa la funzione fopen) e quindi apre il file con i permessi file_name e mode.
Il linguaggio C ha la capacità di lavorare con file temporanei che sono necessari solo durante il lavoro del programma. In questo caso viene utilizzata la funzione
FILE * tmpfile (void);
che crea un file temporaneo sul disco con diritti di accesso "w + b", dopo che il programma termina o dopo aver chiuso il file temporaneo, viene automaticamente eliminato.
18.3. Scrivere - leggere le informazioni
Tutte le azioni di lettura-scrittura dei dati su un file possono essere suddivise in tre gruppi: operazioni di input-output carattere per carattere; operazioni di I/O di linea; bloccare le operazioni di I/O.
Consideriamo le principali funzioni utilizzate in ciascuno di questi tre gruppi di operazioni.
Carattere I/O
Nelle funzioni di I/O carattere per carattere, un carattere viene ricevuto da un file o un carattere viene trasmesso a un file:
Linea I/O
Nelle funzioni di I/O di linea, c'è un trasferimento da un file o verso
Blocco I/O
Le funzioni Block I/O funzionano con interi blocchi
informazione: | |
int fread (void * p, intsize, | - legge n blocchi di dimensione byte ciascuno dal file |
int n, FILE * f) | la f nell'area di memoria con il puntatore p (richiesto |
int fwrite (void * p, intsize, | preallocare memoria per il blocco da leggere); |
- scrive n blocchi di dimensione byte ciascuno dei |
|
int n, FILE * f) | area di memoria con puntatore p al file f. |
L'I/O formattato è prodotto dalle funzioni.
Abbiamo già imparato a scrivere informazioni su un file di testo. - Se non hai imparato, vedi l'ultimo articolo. Racconta e descrive in dettaglio
Ma cosa succede se il file esiste già e abbiamo bisogno di leggere le informazioni da esso per l'elaborazione? Fortunatamente, anche questo è abbastanza semplice. Lascia che ti ricordi che ci sono diverse opzioni per l'implementazione di questo compito, ne ho descritta solo una. Descritto è quello che per qualche motivo personalmente mi sembra il più facile per la percezione.
#includere
intero principale ()
{
carattere s1 //La variabile leggerà la stringa
ifstream in ("C: \\\ FromC \\ miofile.txt"); //Apertura del file per leggere le informazioni
in >> s1; //leggi la riga
in .close() // Chiudi il file
cout<
restituisce 0;
}
Ecco il programma più semplice per leggere la prima riga da un file di testo situato lungo il percorso
C: \\\ FromC \\ miofile.txt -
Poiché questa è una continuazione dell'ultimo articolo, ho deciso di utilizzare il file che abbiamo creato lì. Probabilmente non dovrebbero esserci difficoltà con questo.
Ma torniamo al codice. Innanzitutto, apriamo il file per leggere le informazioni da esso, per questo usiamo il comando ifstream, tra parentesi indichiamo o il nome del file, o il percorso del file, come ho fatto io. (“C: \\\ FromC \\ miofile.txt”);
Quando abbiamo aperto il file per leggere qualcosa da esso, abbiamo dichiarato una variabile come carattere -
carattere s1
Ora non ci resta che assegnare alla variabile il valore della stringa dal file. Lo facciamo come una squadra in
Fai attenzione alle parentesi angolari in >>
In realtà, come si evince dai commenti al codice del programma, affinché la variabile assegni il valore letto, dobbiamo scriverlo dopo in >>
in >> s1;
Questo non sembra essere un compito particolarmente difficile, soprattutto se hai già perfettamente padroneggiato e imparato a usare il materiale dell'articolo precedente: tutto è assolutamente lo stesso, solo 2 comandi sono diversi
Creazione di un file e scrittura di informazioni su di esso C++
distream fuori
( Nome del file );
fuori<< (Stringa scritta);
fuori.chiudere ();
=============================
Lettura del testo da un file e visualizzazione del testo sullo schermo in C++
ifstream in
(Nome del file );
in>>
(Leggiamo la riga);
in.chiudere ();(Chiudi il file)
============================
Scriviamo un semplice programma che leggerà il testo immesso dalla tastiera e lo scriverà su un file:
#includere
#includere
intero principale ()
{
\\
3 linee future
clrsc (); // Pulizia dello schermo
cout<<“Wwedi pervuu stroku”
;
cin >> a; fine;
cout<<“Wwedi wtoruu stroku”
;
cin >> b; fine;
cout<<“Wwedi tretuu stroku”
;
cin >> c; fine;
clrscr (); //
/ * Iniziamo a lavorare con il file * /
ofstream out ("C: \\\ FromC \\ miofile.txt"); //Apertura del file per la scrittura
fuori<Scriviamo la prima riga
fuori<Scriviamo la seconda riga
fuori<
fuori .chiudi (); // Chiudi il file
// Imposta le variabili a zero
per (int i = 0; i<=255
;i
++)
(a = * “”; b = * “”; c = * “”;)
ifstream in (“C: \\\ FromC \\ miofile.txt”);
in >> a >> b >> c; //Leggiamo ogni nuova riga in una nuova variabile
in .chiudi (); // Chiudi il file
/* */
for (i = 0; a! = * “”; i ++)
{
if (i> sizeof (a)) rottura;
cout<
}
cout<<“\n”
; \\
/* */
{
if (i> sizeof (b)) rottura;
cout<
}
cout<<“\n”
; \\
Sposta il cursore su una nuova riga
/* */
for (i = 0; ñ! = * “”; i ++)
{
if (i> sizeof (c)) rottura;
cout<<с
;
}
restituisce 0;
}
===================
Negli esempi sopra, ce n'è uno di questo tipo ENORME difetto. Se proviamo a inserire una riga contenente spazi, il programma non funzionerà come necessario. Probabilmente, non solo io, ma anche molte altre persone sono incappati in questo errore. Pertanto, lascio il codice fornito in modo errato in modo che tu possa vedere cosa potresti incontrare.
Dato che non ci sono libri a casa, ho ricominciato a perlustrare Internet e mi sono imbattuto in un sacco di assurdità di ogni tipo. Tuttavia, in qualche modo ho trovato una soluzione al mio problema.
Mi è stato d'aiuto leggerlo cout supporta i suoi metodi. E su Internet, tutti i consigli vanno all'uso della funzione getline Fortunatamente, ho trovato molto rapidamente come usare questa funzione e poi l'ho usata nel codice.
In generale, vale la pena menzionare e descrivere questa funzione, ma finora non la capisco davvero, capisco solo che deve essere utilizzata e capisco come, quindi fornisco un esempio più corretto del nostro programma sviluppato:
#includere
#includere
intero principale ()
{
carattere a, b, c; \\
3 linee future
clrsc (); // Pulizia dello schermo
/ * Inserisci i valori per le variabili * /
cout<<“Wwedi pervuu stroku”
;
cin.getline (a, sizeof (a)); fine;
cout<<“Wwedi wtoruu stroku”
;
cin.getline (a, sizeof (b)); fine;
cout<<“Wwedi tretuu stroku”
;
cin.getline (a, sizeof (c)); fine;
clrscr (); //Dopo aver inserito i valori, cancellato lo schermo
/ * Iniziamo a lavorare con il file * /
ofstream out ("C: \\\ FromC \\ miofile.txt"); // Apertura del file per la scrittura
fuori<Scriviamo la prima riga
fuori<Scriviamo la seconda riga
fuori<
fuori .chiudi (); // Chiudi il file
// Imposta le variabili a zero
per (int i = 0; i<=255
;i
++)
(a = * “”; b = * “”; c = * “”;)
/ * Continuiamo a lavorare con il file * /
se flusso in (“C: \\\ FromC \\ miofile.txt”);
in.getline (a, sizeof (a));//
un
in.getline (b, sizeof (b));//
Leggiamo una riga in una variabile B
in.getline (c, sizeof (c));
//
Leggiamo una riga in una variabile C
in .chiudi (); // Chiudi il file
/* Leggiamo la prima riga carattere per carattere e la visualizziamo sullo schermo */
for (i = 0; a! = * “”; i ++)
{
if (i> sizeof (a)) rottura;
cout<
}
cout<<“\n”
; \\
Sposta il cursore su una nuova riga
/* Leggiamo la seconda riga carattere per carattere e la visualizziamo sullo schermo */
for (i = 0; b! = * “”; i ++)
{
if (i> sizeof (b)) rottura;
cout<
}
cout<<“\n”
; \\
Sposta il cursore su una nuova riga
/* Leggiamo la terza riga carattere per carattere e la visualizziamo sullo schermo */
for (i = 0; ñ! = * “”; i ++)
{
if (i> sizeof (c)) rottura;
cout<<с[i];
}
getch (); \\In attesa che venga premuto il tasto Invio
restituisce 0;
}
===================
In questo materiale viene analizzato un esempio di lettura delle informazioni carattere per carattere. Dal momento che non ho descritto come lavorare con variabili come char, quindi i principianti potrebbero riscontrare qualche inconveniente nella percezione del codice. Non sapevo di che tipo char ha alcune peculiarità e pensava che tutto fosse più semplice. Pertanto, alcuni punti incomprensibili del programma di cui sopra possono essere letti nel prossimo articolo. lavorare con char v C++ per principianti
Per il resto, l'esempio fornito di come leggere righe da un file di testo in C++ dovrebbe essere disponibile e abbastanza comprensibile. Questa non è l'opzione di implementazione ottimale ora e ho perso alcuni punti importanti, ma poiché stiamo iniziando a imparare il linguaggio C ++, per ora è abbastanza. Più tardi, probabilmente arriverò al punto in cui mi sono perso, ma ora ho solo bisogno di prendere l'essenziale.
Se insieme a voi abbiamo compreso questo materiale, significa che abbiamo fatto un piccolo passo verso la nostra professionalità.
Nota:
rottura;- Questo è il comando che esce dal ciclo. Abbiamo se il contatore del ciclo per diventa maggiore della dimensione dichiarata della variabile carattere, quindi usciamo forzatamente dal ciclo
!= –
questa è la nostra condizione. Questa condizione è indicata dalla disuguaglianza
se (a! = b)- Si legge come se un non uguale B
fine; - Questo sta spostando il cursore su una nuova riga all'interno della console (per quanto ho capito)
Questo comando è simile a "\ N"
Ultimo aggiornamento: 31.10.2015
Classe FileStream rappresenta la capacità di leggere da un file e scrivere su un file. Ti permette di lavorare sia con file di testo che con binari.
Consideriamo le sue proprietà e metodi più importanti:
array - un array di byte in cui verranno inseriti i dati letti dal file
offset rappresenta l'offset, in byte, in cui verranno inseriti i byte letti
count è il numero massimo di byte da leggere. Se il file contiene meno byte, verranno letti tutti.
array - un array di byte da cui i dati verranno scritti nel file
offset - offset in byte nell'array da dove iniziare a scrivere byte nel flusso
count - il numero massimo di byte da scrivere
Proprietà Length: restituisce la lunghezza del flusso in byte
Proprietà Position: restituisce la posizione corrente nel flusso
Metodo di lettura: legge i dati da un file in un array di byte. Accetta tre parametri: int Read (array di byte, int offset, int count) e restituisce il numero di byte letti correttamente. Qui vengono utilizzati i seguenti parametri:
Metodo long Seek (offset lungo, origine SeekOrigin): imposta la posizione nel flusso, offset del numero di byte specificato nel parametro offset.
Metodo Write: scrive i dati da un array di byte in un file. Accetta tre parametri: Write (array di byte, int offset, int count)
FileStream rappresenta l'accesso ai file a livello di byte, quindi, ad esempio, se è necessario leggere o scrivere una o più righe in un file di testo, l'array di byte deve essere convertito in stringhe utilizzando metodi speciali. Pertanto, altre classi vengono utilizzate per lavorare con i file di testo.
Allo stesso tempo, quando si lavora con vari binari che hanno una struttura specifica, FileStream può essere molto utile per recuperare determinate informazioni ed elaborarle.
Diamo un'occhiata a un esempio di lettura-scrittura su un file di testo:
Console.WriteLine ("Inserisci una riga per scrivere nel file:"); string text = Console.ReadLine (); // scrivi nel file using (FileStream fstream = new FileStream (@ "C: \ SomeDir \ noname \ note.txt", FileMode.OpenOrCreate)) (// converti la stringa in byte array di byte = System.Text.Encoding.Default . GetBytes (testo); // scrive un array di byte su un file fstream.Write (array, 0, array.Length); Console.WriteLine ("Testo scritto su un file");) // legge da un file usando ( FileStream fstream = File. OpenRead (@ "C: \ SomeDir \ noname \ note.txt")) (// converte la stringa in byte byte array = new byte; // legge i dati fstream.Read (array, 0, array .Length); // decodifica i byte nella stringa string textFromFile = System.Text.Encoding.Default.GetString (array); Console.WriteLine ("Testo da file: (0)", textFromFile);) Console.ReadLine ();
Diamo un'occhiata a questo esempio. Sia la lettura che la scrittura utilizzano l'istruzione using. Questa istruzione non deve essere confusa con la direttiva using, che include gli spazi dei nomi all'inizio del file di codice. L'istruzione using consente di creare un oggetto in un blocco di codice, al termine del quale viene chiamato il metodo Dispose di questo oggetto e, quindi, l'oggetto viene distrutto. In questo caso, la variabile fstream funge da oggetto.
L'oggetto fstream viene creato in due modi diversi: tramite il costruttore e tramite uno dei metodi statici della classe File.
Qui vengono passati due parametri al costruttore: il percorso del file e l'enumerazione FileMode. Questa enumerazione indica la modalità di accesso ai file e può assumere i seguenti valori:
Aggiungi: se il file esiste, il testo viene aggiunto alla fine del file. Se il file non esiste, viene creato. Il file viene aperto solo per la scrittura.
Crea: viene creato un nuovo file. Se tale file esiste già, viene sovrascritto.
CreaNuovo: viene creato un nuovo file. Se tale file esiste già, l'applicazione genera un errore
Apri: apre un file. Se il file non esiste, viene generata un'eccezione
OpenOrCreate: se il file esiste, viene aperto, in caso contrario ne viene creato uno nuovo
Tronca: se il file esiste, viene sovrascritto. Il file viene aperto solo per la scrittura.
Il metodo statico OpenRead della classe File apre un file per la lettura e restituisce un oggetto FileStream.
Il costruttore FileStream ha anche una serie di overload che consentono di ottimizzare in modo più preciso l'oggetto che crea. Tutte queste versioni possono essere visualizzate su msdn.
Sia la scrittura che la lettura utilizzano l'oggetto di codifica Encoding.Default dallo spazio dei nomi System.Text. In questo caso, utilizziamo due dei suoi metodi: GetBytes per ottenere un array di byte da una stringa e GetString per ottenere una stringa da un array di byte.
Di conseguenza, la riga che abbiamo inserito viene scritta nel file nota.txt... In effetti, questo è un file binario (non un file di testo), sebbene se vi scriviamo solo una riga, saremo in grado di visualizzare questo file in una forma leggibile aprendolo in un editor di testo. Tuttavia, se scriviamo byte casuali in esso, ad esempio:
Fstream.WriteByte (13); fstream.WriteByte (103);
Potremmo avere problemi a capirlo. Pertanto, le classi separate sono destinate a funzionare direttamente con i file di testo: StreamReader e StreamWriter.
Accesso casuale ai file
Non è raro che i file binari rappresentino una struttura specifica. E, conoscendo questa struttura, possiamo prendere l'informazione necessaria dal file o, al contrario, scrivere un certo insieme di byte in un determinato punto del file. Ad esempio, nei file wav, i dati audio stessi iniziano con 44 byte e fino a 44 byte ci sono vari metadati: il numero di canali audio, la frequenza di campionamento, ecc.
Utilizzando il metodo Seek(), possiamo controllare la posizione del cursore del flusso, a partire dal quale viene letto o scritto il file. Questo metodo accetta due parametri: offset e posizione nel file. La posizione nel file è descritta da tre valori:
SeekOrigin.Begin: inizio del file
SeekOrigin.End: fine del file
SeekOrigin.Current: posizione attuale nel file
Il cursore del flusso da cui leggere o scrivere viene spostato in avanti di un offset dalla posizione specificata come secondo parametro. L'offset può essere negativo, quindi il cursore si sposta all'indietro, se positivo, quindi in avanti.
Facciamo un esempio:
Utilizzo di System.IO; utilizzando System.Text; class Program (static void Main (string args) (string text = "hello world"; // scrivi nel file using (FileStream fstream = new FileStream (@ "D: \ note.dat", FileMode.OpenOrCreate)) (// converte la stringa in byte byte input = Encoding.Default.GetBytes (testo); // scrive l'array di byte nel file fstream.Write (input, 0, input.Length); Console.WriteLine ("Il testo è stato scritto nel file"); // sposta il puntatore alla fine del file, cinque byte alla fine del file fstream.Seek (-5, SeekOrigin.End); // meno 5 caratteri dalla fine del flusso // leggi quattro caratteri dalla posizione corrente byte output = new byte; fstream.Read ( output, 0, output.Length); // decodifica i byte in una stringa textFromFile = Encoding.Default.GetString (output); Console.WriteLine (" Text from file: (0)", textFromFile); // worl // sostituisce nel file la parola world con la parola house string replaceText = "house"; fstream.Seek (-5, SeekOrigin.End); // meno 5 caratteri dalla fine del flusso input = Encoding.Default.GetBytes (replaceText); fstream.Write (inpu t, 0, input.Length); // legge l'intero file // restituisce il puntatore all'inizio del file fstream.Seek (0, SeekOrigin.Begin); uscita = nuovo byte; fstream.Read (output, 0, output.Length); // decodifica i byte in una stringa textFromFile = Encoding.Default.GetString (output); Console.WriteLine ("Testo da file: (0)", textFromFile); // ciao casa) Console.Read (); ))
Uscita console:
Testo scritto su file Testo da file: worl Testo da file: ciao casa
La chiamata a fstream.Seek (-5, SeekOrigin.End) riporta il cursore del flusso alla fine dei file di cinque caratteri:
Cioè, dopo aver scritto la riga "ciao mondo" in un nuovo file, il cursore si troverà nella posizione del carattere "w".
Successivamente, leggiamo quattro byte che iniziano con il carattere "w". In questa codifica, 1 carattere rappresenterà 1 byte. Pertanto, leggere 4 byte equivarrà a leggere quattro simboli: "worl".
Quindi di nuovo ci spostiamo alla fine del file, non raggiungendo la fine di cinque caratteri (cioè, sempre dalla posizione del carattere "w"), e scriviamo la stringa "house". Pertanto, la stringa "house" sostituisce la stringa "world".
Chiusura di un flusso
Negli esempi precedenti, il costrutto using viene utilizzato per chiudere il flusso. Dopo che tutte le istruzioni e le espressioni nel blocco using sono state completate, l'oggetto FileStream viene distrutto. Tuttavia, possiamo scegliere un altro modo:
FileStream fstream = null; try (fstream = new FileStream (@ "D: \ note3.dat", FileMode.OpenOrCreate); // operazioni di flusso) catch (Exception ex) () infine (if (fstream! = null) fstream.Close (); )
Se non usiamo il costrutto using, dobbiamo chiamare esplicitamente il metodo Close(): fstream.Close()
La maggior parte dei programmi per computer funziona con i file e quindi diventa necessario creare, eliminare, scrivere, leggere, aprire file. Che cos'è un file? Un file è un insieme denominato di byte che può essere archiviato su un dispositivo di archiviazione. Bene, ora è chiaro che un file è inteso come una certa sequenza di byte, che ha un suo nome univoco, ad esempio un file .txt. I file con lo stesso nome non possono trovarsi in una directory. Il nome del file significa non solo il suo nome, ma anche la sua estensione, ad esempio: file.txt e file.dat — file diversi, anche se hanno lo stesso nome. Esiste un concetto come il nome completo dei file: questo è l'indirizzo completo della directory dei file con il nome del file, ad esempio: D: \ docs \ file.txt. È importante comprendere questi concetti di base, altrimenti sarà difficile lavorare con i file.
Per lavorare con i file, devi connettere il file di intestazione
L'I/O su file è simile all'I/O standard, l'unica differenza è che l'I/O non viene eseguito sullo schermo, ma su un file. Se l'I/O su dispositivi standard viene eseguito utilizzando gli oggetti cin e cout, per organizzare l'I/O su file è sufficiente creare i propri oggetti, che possono essere utilizzati in modo simile agli operatori cin e cout.
Ad esempio, devi creare un file di testo e scrivere la riga Working with files in C++ in esso. Per fare ciò, è necessario eseguire i seguenti passaggi:
- creare un oggetto della classe ofstream ;
- associare l'oggetto classe al file su cui scrivere;
- scrivere una riga su un file;
- chiudere il file.
Perché è necessario creare un oggetto della classe ofstream e non della classe ifstream? Poiché è necessario scrivere su un file e se è necessario leggere dati da un file, verrà creato un oggetto della classe ifstream.
// crea un oggetto da scrivere nel file ofstream / * nome oggetto * /; // un oggetto della classe ofstream
Chiamiamo l'oggetto - fout. Ecco cosa ottieni:
fuori corrente;
Perché abbiamo bisogno di un oggetto? L'oggetto è necessario per poter scrivere sul file. L'oggetto è già stato creato, ma non è associato al file su cui si vuole scrivere la stringa.
Fout.open ("cppstudio.txt"); // collega l'oggetto al file
Attraverso l'operazione punto, otteniamo l'accesso al metodo della classe open(), tra parentesi indichiamo il nome del file. Il file specificato verrà creato nella directory corrente con il programma. Se esiste un file con questo nome, il file esistente verrà sovrascritto da quello nuovo. Quindi, il file è aperto, resta da scrivere la riga richiesta in esso. Questo è fatto in questo modo:
Fout<< "Работа с файлами в С++"; // запись строки в файл
Utilizzando l'operazione stream insieme all'oggetto fout, la riga File Worker in C++ viene scritta in un file. Poiché non è più necessario modificare il contenuto del file, è necessario chiuderlo, ovvero separare l'oggetto dal file.
Fout.close (); //chiudi il file
Risultato: è stato creato un file con la riga Lavorare con i file in C++.
I passaggi 1 e 2 possono essere combinati, ovvero creare un oggetto in una riga e collegarlo a un file. Questo è fatto in questo modo:
Offstream fout ("cppstudio.txt"); // crea un oggetto della classe ofstream e collegalo al file cppstudio.txt
Combiniamo tutto il codice e otteniamo il seguente programma.
// file.cpp: definisce il punto di ingresso per l'applicazione console. #include "stdafx.h" #include
Resta da verificare la correttezza del programma, e per questo apriamo il file cppstudio.txt e guardiamo il suo contenuto, dovrebbe essere... Lavorare con file in C++.
- creare un oggetto della classe ifstream e associarlo al file da cui verrà effettuata la lettura;
- leggere il file;
- chiudere il file.
Il programma mostra due modi di leggere da un file, il primo sta usando l'operazione di trasferimento allo stream, il secondo sta usando la funzione getline () ... Nel primo caso viene letta solo la prima parola, nel secondo viene letta una stringa di 50 caratteri. Ma poiché nel file sono rimasti meno di 50 caratteri, i caratteri vengono letti, inclusi, fino all'ultimo. Nota che leggendo una seconda volta (linea 17) continuò, dopo la prima parola, e non dall'inizio, poiché la prima parola fu letta inlinea 14... Il risultato del programma è mostrato in Figura 1.
Lavorare con i file in C++ Premere un tasto qualsiasi per continuare. ... ...
Figura 1 - Lavorare con i file in C++
Il programma ha funzionato correttamente, ma non è sempre così, anche se tutto è in ordine con il codice. Ad esempio, è stato passato al programma il nome di un file inesistente o è stato commesso un errore nel nome. Cosa poi? In questo caso, non accadrà proprio nulla. Il file non verrà trovato, il che significa che non è possibile leggerlo. Pertanto, il compilatore ignorerà le righe in cui si accede al file. Di conseguenza, il programma uscirà correttamente, ma sullo schermo non verrà mostrato nulla. Sembrerebbe che questa sia una reazione del tutto normale a una situazione del genere. Ma un utente normale non capirà qual è il problema e perché la riga del file non è apparsa sullo schermo. Quindi, per rendere tutto molto chiaro, C ++ fornisce una tale funzione - is_open (), che restituisce valori interi: 1 - se il file è stato aperto con successo, 0 - se il file non è stato aperto. Modifichiamo il programma con l'apertura del file, in modo che se il file non è stato aperto, viene visualizzato un messaggio corrispondente.
// file_read.cpp: definisce il punto di ingresso per l'applicazione console. #include "stdafx.h" #include
Il risultato del programma è mostrato in Figura 2.
Il file non può essere aperto! Premere un tasto qualsiasi per continuare. ... ...
Figura 2 - Lavorare con i file in C++
Come puoi vedere dalla Figura 2, il programma ha segnalato l'impossibilità di aprire il file. Pertanto, se il programma sta lavorando con i file, si consiglia di utilizzare questa funzione, is_open(), anche se si è sicuri che il file esista.
Modalità di apertura dei file
Le modalità di apertura dei file definiscono il modo in cui vengono utilizzati i file. Per impostare la modalità nella classe ios_base, vengono fornite delle costanti che determinano la modalità di apertura dei file (vedere la Tabella 1).
Le modalità di apertura dei file possono essere impostate direttamente durante la creazione di un oggetto o quando si chiama la funzione open() .
Ofstream fout ("cppstudio.txt", ios_base :: app); // apri il file per aggiungere informazioni alla fine del file fout.open ("cppstudio.txt", ios_base :: app); // apri il file per aggiungere informazioni alla fine del file
Le modalità di apertura dei file possono essere combinate utilizzando un'operazione logica bit per bit o| , ad esempio: ios_base :: out | ios_base :: trunc - apre un file per la scrittura, dopo averlo cancellato.
Gli oggetti della classe ofstream, quando sono collegati a file, contengono per impostazione predefinita le modalità per l'apertura dei file ios_base :: out | ios_base :: tronca . Cioè, il file verrà creato se non esiste. Se il file esiste, il suo contenuto verrà eliminato e il file stesso sarà pronto per la scrittura. Gli oggetti della classe ifstream che si collegano a un file hanno la modalità di apertura file predefinita ios_base :: in - il file è aperto in sola lettura. La modalità di apertura dei file è anche chiamata flag, per la leggibilità in futuro useremo proprio questo termine. Non tutti i flag sono elencati nella Tabella 1, ma dovrebbero essere sufficienti per iniziare.
Nota che i flag ate e app sono molto simili nella descrizione, entrambi spostano il puntatore alla fine del file, ma il flag app consente di scrivere solo alla fine del file e il flag ate sposta semplicemente il flag alla fine del file e non limita le posizioni di scrittura.
Sviluppiamo un programma che, utilizzando l'operazione sizeof(), calcolerà le caratteristiche dei tipi di dati di base in C++ e le scriverà su un file. Specifiche:
- il numero di byte allocati per il tipo di dati
- il valore massimo che un particolare tipo di dati può memorizzare.
La scrittura su un file dovrebbe essere eseguita nel seguente formato:
/ * tipo di dati byte valore massimo bool = 1 255.00 char = 1 255.00 short int = 2 32767.00 unsigned short int = 2 65535.00 int = 4 2147483647.00 unsigned int = 4 4294967295.00 long int = 4 2147483647.00 unsigned long int = 4 4294967295.00 float = 4 2147483647.00 long float = 8 9223372036854775800.00 double = 8 9223372036854775800.00 * /
Tale programma è già stato sviluppato in precedenza nella sezione, ma tutte le informazioni sui tipi di dati sono state inviate al dispositivo di output standard e dobbiamo rifare il programma in modo che le informazioni vengano scritte su un file. Per fare ciò, è necessario aprire il file in modalità di registrazione, con il troncamento preliminare delle informazioni sul file corrente ( linea 14). Una volta che il file è stato creato e aperto con successo (righe 16 - 20), invece dell'istruzione cout, in linea 22 usa l'oggetto fout. quindi, invece di uno schermo, le informazioni sul tipo di dati vengono scritte su un file.
// write_file.cpp: definisce il punto di ingresso per l'applicazione console. #include "stdafx.h" #include
È impossibile non notare che le modifiche al programma sono minime e tutte dovute al fatto che l'input/output standard e l'input/output del file vengono utilizzati esattamente allo stesso modo. Alla fine del programma, atlinea 45abbiamo chiuso esplicitamente il file, anche se non richiesto, è considerata una buona pratica di programmazione. Vale la pena notare che tutte le funzioni e i manipolatori utilizzati per la formattazione dell'I/O standard sono rilevanti anche per l'I/O dei file. Pertanto, non si sono verificati errori quando l'operatore cout è stato sostituito da un oggetto fout.