{"id":7473,"date":"2011-08-22T15:01:32","date_gmt":"2011-08-22T13:01:32","guid":{"rendered":"http:\/\/www.devapp.it\/wordpress\/?p=7473"},"modified":"2011-10-05T12:28:21","modified_gmt":"2011-10-05T10:28:21","slug":"17-la-gestione-dei-file-in-c","status":"publish","type":"post","link":"https:\/\/www.devapp.it\/wordpress\/17-la-gestione-dei-file-in-c\/","title":{"rendered":"17. La gestione dei file in C"},"content":{"rendered":"<p><a href=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/corso-completo-c-la-gestione-dei-file-in-C-00.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/08\/corso-completo-c-la-gestione-dei-file-in-C-00.jpg\" alt=\"corso-completo-c-la-gestione-dei-file-in-C-00\" title=\"corso-completo-c-la-gestione-dei-file-in-C-00\" width=\"200\" height=\"100\" class=\"alignleft size-full wp-image-7479\" \/><\/a> Fino ad oggi tutti gli esempi di codice che abbiamo scritto hanno richiesto l&#8217;input manuale dell&#8217;utente oppure i valori necessari per il calcolo sono stati inseriti direttamente all&#8217;interno del codice e, cosa pi\u00f9 grave, tutti i risultati ottenuti venivano persi immediatamente alla terminazione del programma.<\/p>\n<p>Questo approccio pu\u00f2 andar bene per un programma d&#8217;esempio ma \u00e8 chiaro che un programma vero ha quasi sempre la necessit\u00e0 di leggere o scrivere su un file.<\/p>\n<p>La gestione dei file \u00e8 responsabilit\u00e0 del sistema operativo quindi, analogamente a quello che avviene con le funzioni *alloc,  il nostro programma chieder\u00e0 al sistema operativo di poter scrivere su un determinato file oppure di leggerne il contenuto e questi (il sistema operativo) risponder\u00e0 positivamente o negativamente a seconda di una serie di informazioni quali ad esempio: i permessi del file, i permessi della partizione etc.<!--more--><\/p>\n<h5>Una piccola digressione sistemistica<\/h5>\n<p>Se avete un p\u00f2 di conoscenza del mondo linux saprete sicuramente che questo sistema operativo permette di gestire i permessi sul file system in modo veramente granulare e sicuro. Cosa succederebbe se un programma, scritto in qualsivoglia linguaggio, riuscisse a bypassare il controllo del sistema operativo per accedere direttamente ai dati grezzi scritti sull&#8217;hard disk? Succederebbe che tutta questa architettura di permessi fallirebbe miseramente e risulterebbe quindi inutile.<\/p>\n<p>Ma allora cosa avviene in realt\u00e0?<\/p>\n<p>Quando un programma viene avviato eredita i permessi dell&#8217;utente che lo ha lanciato e quando ha bisogno di scrivere su un file chiede al sistema operativo qualcosa come &#8220;sono l&#8217;utente X, posso scrivere su questo file?&#8221;, il sistema operativo verifica se l&#8217;utente X ha i permessi di scrittura su quella cartella e approva o meno la scrittura.<\/p>\n<p>Per questo motivo \u00e8 necessario che alcuni programmi vengano lanciati come root oppure tramite il comando &#8220;sudo&#8221;, perch\u00e9 altrimenti non avrebbero i permessi di scrivere sui file necessari. Un esempio per tutti: passwd.<\/p>\n<h4>File Handle<\/h4>\n<p>A ben guardare nei nostri esempi abbiamo gi\u00e0 utilizzato dei file anche se non esplicitamente. Sto parlando dei due file denominati standard input (stdin) e standard output (stdout). Le funzioni che abbiamo incontrato come <em>printf<\/em> o <em>scanf<\/em> sono delle versioni semplificate delle funzioni che vedremo oggi e hanno come limitazione quella di funzionare esclusivamente su questi due file. Ma come si fa a lavorare quindi su qualsiasi altro file? La funzione principale si chiama <em>fopen<\/em> e il suo prototipo \u00e8 questo: (<a href=\"http:\/\/www.manpagez.com\/man\/3\/fopen\/\" target=\"_blank\">link<\/a>)<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nFILE *fopen(const char *restrict filename, const char *restrict mode);\r\n<\/pre>\n<p>Spieghiamola in dettaglio:<\/p>\n<p>Vediamo innanzitutto che la funzione restituisce un puntatore ad un tipo di dato particolare, il tipo FILE. Un puntatore a questo tipo di variabile viene chiamato &#8220;file handle&#8221; o anche &#8220;file descriptor&#8221; e viene utilizzato in tutte le funzioni che devono lavorare su questo file.<\/p>\n<p>Il successivo parametro \u00e8 un puntatore a char (ignoriamo &#8220;const&#8221; e &#8220;restrict&#8221; al momento) e non dovreste avere difficolt\u00e0, se avete seguito la lezione precedente, a capire che si tratta quindi di una &#8220;stringa&#8221; che indica il nome del file. Attenzione a questo parametro, se specifichiamo solo il nome del file il programma lo cercher\u00e0 nella sua working directory (la directory dalla quale il programma \u00e8 stato lanciato) altrimenti bisogner\u00e0 specificare tutto il percorso.<\/p>\n<p>Il terzo parametro \u00e8 anch&#8217;esso un puntatore a char e specifica il tipo di accesso al file richiesto, se in lettura\/scrittura etc. I valori pi\u00f9 usati sono:<\/p>\n<ul>\n<li>&#8220;r&#8221;  Apre il file in lettura. Se il file non esiste viene restituito NULL<\/li>\n<li>&#8220;r+&#8221; Apre il file in lettura e scrittura. Se il file non esiste viene restituito NULL<\/li>\n<li>&#8220;w&#8221; Apre il file in scrittura cancellandone il contenuto precedente. Se il file non esiste lo crea.<\/li>\n<li>&#8220;w+&#8221; Apre il file in lettura e scrittura cancellandone il contenuto precedente. se il file non esiste lo crea.<\/li>\n<li>&#8220;a&#8221;        Apre il file in scrittura. I dati scritti sul file vengono accodati a quelli gi\u00e0 esistenti. Se il file non esiste viene creato<\/li>\n<li>&#8220;a+&#8221; Apre il file in lettura e escrittura. I dati scritti sul file vengono accodati a quelli gi\u00e0 esistenti. Se il file non esiste viene creato<\/li>\n<\/ul>\n<p>Una porzione di codice per accedere in lettura e scrittura sul file &#8220;prova.txt&#8221; presente nella working directory del programma potrebbe essere:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n\r\nint main(int argc, char **argv) {\r\n\r\n        FILE *f; \/\/dichiarazione del file handle\r\n\r\n        f = fopen(\"prova.txt\", \"r+\"); \/\/tentativo di apertura del file.\r\n\r\n        if (! f ) { \/\/verifico se il file handle restituito dalla funzione \u00e8 null o meno.\r\n\r\n                \/\/se \u00e8 null esco dal programma riportando un errore\r\n\r\n                printf(\"Impossibile aprire il file: prova.txt\");\r\n\r\n        return 1;\r\n\r\n}\r\n\r\n\/\/qui posso inserire il codice per la lettura\/scrittura\r\n\r\nreturn 0;\r\n\r\n}\r\n<\/pre>\n<p>\u00c8 importante ricordarsi di chiudere i file che si sono aperti, per indicare al sistema operativo che abbiamo terminato di utilizzare quel file, e lo si fa tramite la funzione <em>fclose<\/em> il cui prototipo \u00e8:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nint fclose(FILE *stream);\r\n<\/pre>\n<p>Questa funzione chiude il file il cui handle le viene passato come parametro e restituisce 0 se la chiusura \u00e8 andata a buon fine, viceversa restituisce EOF (End Of File) ed in quel caso bisognerebbe indagare meglio sull&#8217;accaduto.<\/p>\n<p>Ho usato il condizionale perch\u00e9 non vorrei fare la figura di chi predica bene e razzola male&#8230; <em>fclose<\/em> fa parte di quelle funzioni per le quali andrebbe sempre analizzato il valore di ritorno ma che, vista la scarsa probabilit\u00e0 di fallimento, spesso dimentico di verificare. Sapete che anche <em>printf<\/em> ha un valore di ritorno che andrebbe valutato per ogni chiamata? Potremmo chiamare questo approccio &#8220;quite optimistic programming&#8221; \ud83d\ude42<\/p>\n<h4>L&#8217;indicatore di posizione<\/h4>\n<p>Nella gestione dei file in C \u00e8 importante tenenere a mente il concetto di indicatore di posizione. Possiamo pensare all&#8217;indicatore di posizione come al cursore nei programmi di editing di testo: un segnaposto che indica dove verr\u00e0 aggiunto il testo in fase di scrittura.<\/p>\n<p>Se il file viene aperto con &#8220;r&#8221;, &#8220;r+&#8221;, &#8220;w&#8221;, &#8220;w+&#8221; allora l&#8217;indicatore di posizione viene posto all&#8217;inizio del file, se invece viene aperto con &#8220;a&#8221; viene posto alla fine.<\/p>\n<p>Quando si effettua una lettura o scrittura su un file l&#8217;indicatore di posizione si sposta conseguentemente, quindi se abbiamo aperto il file con &#8220;r&#8221;, poi abbiamo scritto sul file una stringa di 128 caratteri avremo l&#8217;indicatore in posizione 128.<\/p>\n<p>Per gestire l&#8217;indicatore di posizione abbiamo inoltre tre funzioni specifiche, che sono:<\/p>\n<ul>\n<li>long ftell(FILE *stream);<\/li>\n<li>void rewind(FILE *stream);<\/li>\n<li>int fseek(FILE *stream, long offset, int whence);<\/li>\n<\/ul>\n<p><strong>ftell<\/strong>: restituisce un long che indica la posizione corrente dell&#8217;indicatore di posizion.<\/p>\n<p><strong>rewind<\/strong>: (complimenti per il nome) riporta l&#8217;indicatore di posizione in posizione 0<\/p>\n<p><strong>fseek<\/strong>: sposta l&#8217;indicatore di posizione di un valore pari a offset (anche negativo) a partire dalla posizione whence. Per quest&#8217;ultimo parametro esistono tre macro che sono SEEK_SET, SEEK_CUR, e SEEK_END e indicano rispettivamente l&#8217;inizio del file, la posizione corrente dell&#8217;indicatore di posizione e la fine del file.<\/p>\n<p>Vediamone l&#8217;utilizzo in un programma completo:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n\r\nvoid printIndicatorPosition(FILE *f){\r\n\r\n  printf(\"L' indicatore si trova in posizione: %ld\\n\",ftell(f));\r\n\r\n}\r\n\r\nint main(int argc, char **argv) {\r\n\r\n  FILE *f;\r\n\r\n  \/* apro il file in sola lettura *\/\r\n\r\n  f = fopen(\"prova.txt\",\"r\");\r\n\r\n  if ( ! f ) {\r\n\r\n    printf(\"Impossibile aprire il file\\n\");\r\n\r\n    return 1;\r\n\r\n  }\r\n\r\n  printf(\"Apertura ok\\n\");\r\n\r\n  \/* Il cursore dovrebbe essere in posizione zero *\/\r\n\r\n  printIndicatorPosition(f);\r\n\r\n  fseek(f,5,SEEK_SET);\r\n\r\n  \/* Il cursore dovrebbe essere in posizione 5 *\/\r\n\r\n  printIndicatorPosition(f);\r\n\r\n  rewind(f);\r\n\r\n  \/* Il cursore dovrebbe essere nuovamente in posizione 0 *\/\r\n\r\n  printIndicatorPosition(f);\r\n\r\n  return 0;\r\n\r\n}\r\n<\/pre>\n<h4>Funzioni per la lettura<\/h4>\n<p>Esistono diverse funzioni per la lettura da file, alcune pi\u00f9 a basso livello di altre, ma tutte iniziano a leggere dalla posizione attuale dell&#8217;indicatore di posizione.<\/p>\n<h5>fread()<\/h5>\n<p>La funzione pi\u00f9 a basso livello \u00e8 la fread(), il suo utilizzo pu\u00f2 non essere immediato per qualcuno ed \u00e8 una funzione che rientra nella categoria delle funzioni &#8220;i know what i&#8217;m doing&#8221; \ud83d\ude42 il suo prototipo \u00e8 :<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nsize_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);\r\n<\/pre>\n<p>e forse non c&#8217;\u00e8 modo pi\u00f9 chiaro di spiegarla di come fa la sua pagina di man.<\/p>\n<blockquote><p>The function <a href=\"http:\/\/swoolley.org\/man.cgi\/3\/fread\" target=\"_blank\">fread<\/a> reads <em>nmemb<\/em> elements of data, each <a href=\"http:\/\/swoolley.org\/man.cgi\/1\/size\" target=\"_blank\">size<\/a> <a href=\"http:\/\/swoolley.org\/man.cgi\/3\/bytes\" target=\"_blank\">bytes<\/a>  long, from  the  stream  pointed  to  by <em>stream<\/em>, storing them <a href=\"http:\/\/swoolley.org\/man.cgi\/1\/at\" target=\"_blank\">at<\/a> the location given by <em>ptr<\/em>.<\/p><\/blockquote>\n<p>Per i non anglofoni: La funzione fread legge nmemb elementi, ciascuno di dimensione size bytes, dallo stream puntato da stream e memorizza il tutto nella variabile puntata dal puntatore ptr.<\/p>\n<p>Chiss\u00e0 perch\u00e9 quando vedo questi prototipi cos\u00ec grezzi mi viene in mente il demenziale tormentone &#8220;Non c&#8217;\u00e8 problema, tu mi dici quello che devo fare ed io lo faccio&#8221;. (e con questa mi sono giocato la reputazione!)<\/p>\n<p>Facciamo subito un esempio per provare la funzione fread(), supponiamo avere un file di testo cos\u00ec formato<\/p>\n<pre>\r\nAAAAA\r\n\r\nBBBBB\r\n\r\nCCCCC\r\n\r\n..\r\n\r\nZZZZZ\r\n<\/pre>\n<p>Se non volete impazzire per crearlo ecco lo script bash che ho usato io:<\/p>\n<pre>\r\n#!\/bin\/bash                                                              \r\n\r\nchr() {\r\n  printf \\\\$(printf '%03o' $1)\r\n}\r\n\r\nfor i in {65..90}\r\n\r\ndo\r\n    echo $(chr $i)$(chr $i)$(chr $i)$(chr $i)$(chr $i)\r\n\r\ndone\r\n<\/pre>\n<p>Quello che vogliamo fare \u00e8 scrivere un programma che legga l&#8217;intero file inserendo una riga alla volta in un array di caratteri. Poich\u00e9 conosciamo esattamente il formato del file possiamo usare tranquillamente la funzione fread(), in questo modo:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n\r\n#define NUM_ROW     25\r\n#define NUM_CHAR    5\r\n\r\nint main(int argc, char **argv) {\r\n\r\n  FILE *f;\r\n\r\n  char row[NUM_CHAR + 1]; \/* Un array per contenere i caratteri letti, l'ultimo sar\u00e0 lo \\0 *\/\r\n\r\n  int i,j; \/* due interi  per i cicli for *\/\r\n\r\n  \/* apro il file in sola lettura *\/\r\n\r\n  f = fopen(\"lettere\",\"r\");\r\n\r\n  if ( ! f ) {\r\n    printf(\"Impossibile aprire il file\\n\");\r\n    return 1;\r\n  }\r\n\r\n  printf(\"Apertura ok\\n\");\r\n\r\n  for (i = 0; i < NUM_ROW; i++ ){\r\n    \/* Leggo esattamente NUM_CHAR caratteri e li memorizzo nell'array row *\/\r\n    fread(row,sizeof(char),NUM_CHAR,f);\r\n\r\n    \/* Aggiungo lo \\0 alla fine dell'array, anche se sicuramente c'\u00e8 gi\u00e0 *\/\r\n    row[NUM_CHAR] = '\\0';\r\n\r\n    printf(\"Ho letto la stringa: %s  \\n\", row);\r\n\r\n    \/* Abbiamo letto esattamente NUM_CHAR caratteri, adesso vogliamo scartare lo \\n che c'\u00e8 alla fine di ogni riga                                                                \r\n    *  quindi sposto il cursore avanti di una posizione.                                                                                                 \r\n    *\/\r\n\r\n    fseek(f,1,SEEK_CUR);\r\n  }\r\n\r\n  fclose(f);\r\n  return 0;\r\n}\r\n<\/pre>\n<h5>fgetc()<\/h5>\n<p>La funzione fgetc() \u00e8 pi\u00f9 semplice da usare rispetto alla fread() ma ovviamente \u00e8 pi\u00f9 limitata perch\u00e9 non pu\u00f2 leggere dati di dimensione arbitraria, ma legge un solo carattere alla volta. L'esempio precedente pu\u00f2 essere modificato per usare fgetc in questo modo:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n\r\n#define NUM_ROW 25\r\n#define NUM_CHAR 5\r\n\r\nint main(int argc, char **argv) {\r\n\r\n  FILE *f;\r\n\r\n  char row[NUM_CHAR + 1]; \/* Un array per contenere i caratteri letti, l'ultimo sar\u00e0 lo \\0 *\/\r\n\r\n  int i,j; \/* due interi  per i cicli for *\/\r\n\r\n  \/* apro il file in sola lettura *\/\r\n\r\n  f = fopen(\"lettere\",\"r\");\r\n\r\n  if ( ! f ) {\r\n    printf(\"Impossibile aprire il file\\n\");\r\n    return 1;\r\n  }\r\n\r\n  printf(\"Apertura ok\\n\");\r\n\r\n  for (i = 0; i < NUM_ROW; i++ ){\r\n    for        (j = 0;        j < NUM_CHAR; j++) {\r\n       \/* leggo un singolo carattere alla volta *\/\r\n       row[j] = fgetc(f);\r\n    }\r\n    \/*aggiungo il solito \\0 alla fine *\/\r\n    row[NUM_CHAR] = '\\0';\r\n\r\n    printf(\"Ho letto la stringa: %s \\n\", row);\r\n\r\n    \/* per skippare lo \\n posso anche effettuare una lettura a vuoto *\/\r\n\r\n    fgetc(f);\r\n  }\r\n\r\n  fclose(f);\r\n  return 0;\r\n}\r\n<\/pre>\n<h5>fgets()<\/h5>\n<p>Se la necessit\u00e0 \u00e8 quella di leggere una riga alla volta allora si pu\u00f2 usare anche la funzione fgets(), il cui prototipo \u00e8:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar * fgets(char *restrict s, int n, FILE *restrict stream);\r\n<\/pre>\n<p>La funzione fgets() legge dal file stream righe di lunghezza massima n e le memorizza nella variabile puntata da s. Questa funzione ha, a mio avviso, la pecca di mantenere all'interno della stringa letta anche il carattere \\n finale, il che costringe spesso ad un'operazione di pulizia. Ha il vantaggio per\u00f2 di inserire autonomamente il carattere \\0.<\/p>\n<p>Vediamo come risulterebbe il solito esempio se usassimo questa funzione:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n#include <string.h>\r\n\r\n#define NUM_ROW  25\r\n#define NUM_CHAR 128\r\n\r\nint main(int argc, char **argv) {\r\n\r\n  FILE *f;\r\n\r\n  char row[NUM_CHAR + 1]; \/* Un array per contenere i caratteri letti, l'ultimo sar\u00e0 lo \\0 *\/\r\n\r\n  int i,j; \/* due interi  per i cicli for *\/\r\n\r\n  \/* apro il file in sola lettura *\/\r\n\r\n  f = fopen(\"lettere\",\"r\");\r\n\r\n  if ( ! f ) {\r\n    printf(\"Impossibile aprire il file\\n\");\r\n    return 1;\r\n  }\r\n\r\n  printf(\"Apertura ok\\n\");\r\n\r\n  for (i = 0; i < NUM_ROW; i++ ){\r\n    \/* Leggo una riga alla volta, ho fissato la lunghezza a 128 caratteri, fingendo di ignorare che le righe sono lunghe 6 caratteri *\/\r\n    fgets(row,NUM_CHAR,f);\r\n\r\n    \/* Verifico se alla fine della stringa fgets mi ha lasciato lo \\n, se \u00e8 cos\u00ec lo sostituisco con uno \\0 *\/\r\n    if(row[strlen(row) - 1] == '\\n') {\r\n      row[strlen(row)  - 1] = '\\0';\r\n    }\r\n\r\n    printf(\"Ho letto la stringa: %s  \\n\", row);\r\n  }\r\n\r\n  fclose(f);\r\n  return 0;\r\n}\r\n<\/pre>\n<h4>EOF<\/h4>\n<p>In questi esempi siamo stati un p\u00f2 fortunati, perch\u00e9 sapevamo gi\u00e0 che il file era composto esattamente da 25 righe e quindi abbiamo sfruttato un semplice FOR per eseguire la lettura. Ma cosa succede se il file pu\u00f2 essere arbitrariamente lungo? In quel caso non possiamo far altro che continuare a leggere finch\u00e9  non raggiungiamo la fine del file, quindi ci toccher\u00e0 utilizzare un WHILE, ma quale sar\u00e0 il test per verificare se abbiamo o meno raggiunto la fine del file? Dipende dalla funzione che stiamo utilizzando, perch\u00e9 ciascuna funzione ha le sue particolarit\u00e0:<\/p>\n<h5>fread()<\/h5>\n<p>Questa funzione restituisce il numero di byte effettivamente letti, quindi pu\u00f2 essere usato il suo valore di ritorno per verificare se il file \u00e8 terminato o meno, in aggiunta pu\u00f2 essere usata anche la funzione feof() che indica se si \u00e8 raggiunta o meno la fine del file. Ecco uno stralcio di esempio:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nchar row[128];\r\n\r\nFILE *f;\r\n\r\nif( (f = fopen( \"prova.txt\", \"r\" )) == NULL )\r\n\r\nreturn 1;\r\nwhile( !feof( stream ) )\r\n\r\n{\r\n\r\ncount = fread( row, sizeof( char ), 127, stream );\r\n\r\nif (count < 127)\r\n\r\n        \/\/probabilmente si \u00e8 raggiunta la fine del file.\r\n\r\n}\r\n<\/pre>\n<h5>fgetc()<\/h5>\n<p>La funzione fgetc restituisce un carattere alla volta quindi \u00e8 facile rendersi conto della fine del file, infatti basta inserire la lettura direttamente come condizione del while, come in questo esempio:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nwhile(fgets(s, MAX_BUFF, file) != EOF){\r\n\r\n}\r\n<\/pre>\n<h5>fgets()<\/h5>\n<p>Anche in questo caso \u00e8 piuttosto semplice rilevare la fine del file, infatti baster\u00e0 inserire la lettura come condizione del while:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nwhile ( fgets(line, LINE_LENGTH, fp) != NULL) {\r\n\r\n}\r\n<\/pre>\n<h4>Le funzioni per la scrittura<\/h4>\n<p>Una buona notizia per voi: se avete letto e capito la parte precedente di questo articolo siete praticamente ad un passo da gestire i file in totale libert\u00e0 e autonomia, perch\u00e9 le funzioni per la scrittura su file sono praticamente identiche a quelle per la lettura. Vediamole seguendo lo stesso approccio precedente, dalle funzioni di basso livello a quelle di alto livello.<\/p>\n<h5>fwrite()<\/h5>\n<p>Il prototipo della funzione \u00e8 il seguente:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nsize_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);\r\n<\/pre>\n<p>e come si pu\u00f2 notare \u00e8 praticamente identico al prototipo della funzione fread(), questa funzione scrive <em>nmemb<\/em> elementi composti da size byte ciascuno sullo stream <em>stream<\/em>, leggendoli dalla variabile puntata da <em>ptr<\/em>. Vediamone subito un esempio.<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n\r\nint main(int argc, char **argv) {\r\n\r\n  FILE *f;\r\n\r\n  char buf[5] =        \"Ciao\";\r\n\r\n  \/* apro il file in sola lettura *\/\r\n  f = fopen(\"file.txt\",\"w\");\r\n\r\n  if ( ! f ) {\r\n    printf(\"Impossibile aprire il file\\n\");\r\n    return 1;\r\n  }\r\n\r\n  printf(\"Apertura ok\\n\");\r\n\r\n  fwrite(buf,sizeof(char),4,f);\r\n\r\n  fclose(f);\r\n  return 0;\r\n\r\n}\r\n<\/pre>\n<h5>fputc()<\/h4>\n<p>Il duale della funzione fgetc() \u00e8 la funzione fputc(). La sua funzione \u00e8 quella di scrivere un carattere alla volta su un file. Il prototipo \u00e8 :<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nint fputc(int c, FILE *stream);\r\n<\/pre>\n<p>Ed ecco un esempio di utilizzo:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n\r\nint main(int argc, char **argv) {\r\n\r\n  FILE *f;\r\n  char buf[5] = \"Ciao\";\r\n  int i;\r\n\r\n  \/* apro il file in sola lettura *\/\r\n  f = fopen(\"file.txt\",\"w\");\r\n\r\n  if ( ! f ) {\r\n    printf(\"Impossibile aprire il file\\n\");\r\n    return 1;\r\n  }\r\n\r\n  printf(\"Apertura ok\\n\");\r\n\r\n  for (i = 0; i < 5; i++){\r\n    fputc(buf[i],f);\r\n  }\r\n\r\n  fclose(f);\r\n  return 0;\r\n}\r\n<\/pre>\n<h5>fputs()<\/h5>\n<p>Come avrete gi\u00e0 intuito la funzione fputs() \u00e8 la duale della fgets() ed il suo utilizzo \u00e8 molto semplice. La sua funzione \u00e8 quella di scrivere una stringa (che deve essere terminata con uno \\0) sul file. Attenzione che lo \\0 non verr\u00e0 scritto sul file. Il prototipo \u00e8 il seguente:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\nint fputs(const char *s, FILE *stream);\r\n<\/pre>\n<p>ed ecco l'esempio di utilizzo:<\/p>\n<pre lang=\"c\" line=\"1\" escaped=\"true\">\r\n#include <stdio.h>\r\n\r\nint main(int argc, char **argv) {\r\n\r\n  FILE *f;\r\n  char buf[5] = \"Ciao\";\r\n  int i;\r\n\r\n  \/* apro il file in sola lettura *\/\r\n  f = fopen(\"file.txt\",\"w\");\r\n\r\n  if ( ! f ) {\r\n    printf(\"Impossibile aprire il file\\n\");\r\n    return 1;\r\n  }\r\n\r\n  printf(\"Apertura ok\\n\");\r\n  fputs(buf,f);\r\n  fclose(f);\r\n\r\n  return 0;\r\n}\r\n<\/pre>\n<p>Ed eccoci giunti al termine di questa lunga lezione. Adesso siete perfettamente in grado di gestire i file con il linguaggio C, per qualsiasi dubbio non esitate a chiedere nell'<a href=\"http:\/\/forum.devapp.it\/forumdisplay.php?43-Corso-Completo-di-Programmazione-in-C\" target=\"_blank\">apposita sezione<\/a> dedicata al corso sul nostro forum.<\/p>\n<p>Alla prossima<br \/>\nIgnazioC<\/p>\n<h4>Letture consigliate:<\/h4>\n<p><a href=\"http:\/\/www.amazon.it\/gp\/search\/ref=as_li_qf_sp_sr_il_tl?ie=UTF8&#038;keywords=887192200X&#038;tag=de0d-21&#038;index=aps&#038;linkCode=as2&#038;camp=3370&#038;creative=23322\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/03\/C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP.jpg\" alt=\"C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP\" title=\"C-Corso-Completo-di-Programmazione-kernighan-ritchie-devAPP\" width=\"54\" height=\"75\" class=\"alignleft size-full wp-image-7803\" \/><\/a> <a href=\"http:\/\/www.amazon.it\/gp\/search\/ref=as_li_qf_sp_sr_il_tl?ie=UTF8&#038;keywords=887192200X&#038;tag=de0d-21&#038;index=aps&#038;linkCode=as2&#038;camp=3370&#038;creative=23322\" target=\"_blank\"><strong>Il linguaggio C. Principi di programmazione e manuale di riferimento (Accademica) <\/strong><\/a><br \/>\n<em>Brian W. Kernighan - Dennis M. Ritchie<\/em><br \/>\n<strong>Editore:<\/strong> Pearson | <strong>Lingua:<\/strong> Italiano | <strong>Brossura:<\/strong> 313 pagine<br \/>\n<strong>Prezzo Listino:<\/strong> <del datetime=\"2011-09-03T10:00:08+00:00\">EUR 27,00<\/del><br \/>\n<strong>Prezzo Promozione:<\/strong> EUR 22,95 con Spedizione gratuita<\/p>\n<p><a href=\"http:\/\/www.amazon.it\/gp\/product\/8850329547\/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&#038;tag=de0d-21&#038;linkCode=as2&#038;camp=3370&#038;creative=23322&#038;creativeASIN=8850329547\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2011\/09\/C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP.jpg\" alt=\"C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP\" title=\"C-Corso-Completo-di-Programmazione-Deitel-Deitel-devAPP\" width=\"54\" height=\"75\" class=\"alignleft size-full wp-image-7550\" \/><\/a> <a href=\"http:\/\/www.amazon.it\/gp\/product\/8850329547\/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&#038;tag=de0d-21&#038;linkCode=as2&#038;camp=3370&#038;creative=23322&#038;creativeASIN=8850329547\" target=\"_blank\"><strong>C. Corso completo di programmazione<\/strong><\/a><br \/>\n<em>Paul J. Deitel - Harvey M. Deitel<\/em><br \/>\n<strong>Editore:<\/strong> Apogeo | <strong>Lingua:<\/strong> Italiano | <strong>Brossura:<\/strong> 640 pagine<br \/>\n<strong>Prezzo Listino:<\/strong> <del datetime=\"2011-09-03T10:00:08+00:00\">EUR 39,00<\/del><br \/>\n<strong>Prezzo Promozione:<\/strong> EUR 33,15 con Spedizione gratuita<\/p>\n<p><center><br \/>\n<a href=\"http:\/\/www.devapp.it\/wordpress\/supporto-applicazioni\/le-applicazioni-dei-nostri-autori\/parole-vietate-di-ignazio-calo\" target=\"_blank\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter\" src=\"http:\/\/www.devapp.it\/wordpress\/wp-content\/uploads\/2010\/02\/bannerIgnazioc.png\" alt=\"\" width=\"480\" height=\"100\" \/><\/a><br \/>\n<\/center><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Fino ad oggi tutti gli esempi di codice che abbiamo scritto hanno richiesto l&#8217;input manuale dell&#8217;utente oppure&#8230;<\/p>\n","protected":false},"author":53,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[569],"tags":[593,588,887,724,723,885,886,882,880,889,890,884,888,881,241,883],"class_list":["post-7473","post","type-post","status-publish","format-standard","hentry","category-corso-completo-di-c","tag-corso-completo-di-c-2","tag-corso-di-c","tag-eof-c","tag-esempi-codice-programmazione-c","tag-esercizi-programmazione-c","tag-fgetc-c","tag-fgets-c","tag-file-handle-c","tag-file-in-c","tag-fputc-c","tag-fputs-c","tag-fread-c","tag-fwrite-c","tag-gestione-file-in-c","tag-ignazio-calo","tag-indicatore-di-posizione-file-in-c"],"acf":[],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/comments?post=7473"}],"version-history":[{"count":11,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7473\/revisions"}],"predecessor-version":[{"id":7821,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/posts\/7473\/revisions\/7821"}],"wp:attachment":[{"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/media?parent=7473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/categories?post=7473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devapp.it\/wordpress\/wp-json\/wp\/v2\/tags?post=7473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}