Il File-System Manipolazioni di file in ambiente Linux ISO C Standard Library v L’I/O ANSI C si può effettuare attraverso diverse catagorie di funzioni Ø Un carattere alla volta Ø Una riga alla volta Ø I/O formattato Ø R/W diretto v Si osservi che il kernel UNIX non differenzia file ASCII da file Binari Ø Il carattere “b” durante l’apertura di un file non ha effetto ● “r”==“rb”, “w”==“wb”, etc. Apertura e chiusura di un file #include <stdio.h> FILE *fopen (char *path, char *type); FILE *fclose (FILE *fp); v Metodi di accesso Ø r, rb, w, wb, a, ab r+, r+b, etc. Ø Il kernel UNIX non differenzia file ASCII da file Binari ● “b” durante l’apertura di un file non ha effetto, e.g. “r”==“rb”, “w”==“wb”, etc. I/O a caratteri #include <stdio.h> int getc (FILE *fp); int fgetc (FILE *fp); int putc (int c, FILE *fp); int fputc (int c, FILE *fp); v La funzione getchar è equivalente a getc (stdin) v La funzione putchar è equivalente a putc (c, stdout) I/O a righe #include <stdio.h> char *fgets (char *buf, int n, FILE *fp); char gets (char *buf); int *fputs (char *buf, FILE *fp); int puts (char *buf); v Le righe sono delimitate dal carattere “new line” v Occorre specificare la lunghezza massima delle righe I/O formattato #include <stdio.h> int scanf (char format, …); int fscanf (FILE *fp, char format, …); int printf (char format, …); int fprintf (FILE *fp, char format, …); v Elevata duttilità sulla manipolazione di dati Ø Formati Ø Conversioni I/O diretto #include <stdio.h> size_t fread (void *ptr, size_t size, size_t nObj, FILE *fp); size_t fwrite (void *ptr, size_t size, size_t nObj, FILE *fp); v Ogni operazione di I/O si occupa di leggere o scrivere un oggetto di dimensione specifica v Valore di ritorno Ø Numero di oggetti letti oppure scritti Ø Se il valore non corrisponde si ha avuto un errore oppure raggiunta la fine del file I/O diretto #include <stdio.h> size_t fread (void *ptr, size_t size, size_t nObj, FILE *fp); size_t fwrite (void *ptr, size_t size, size_t nObj, FILE *fp); v Spesso utilizzate per gestire file binari Ø R/W di intere strutture Ø Potenziali problemi nel gestire dati su archittetture diverse per problemi di compatibilità dei formati (e.g., interi, formati, etc.) Esempi float data[10]; if (fwrite(&data[2],sizeof(float),4,fp)!=4) { fprintf (stderr, "Error: Write %d).\n", n); } } struct { char name[L]; int n; float avg; } item; if (fwrite(&item,sizeof(item),1,fp))!=1) { fprintf (stderr, "Error: Write %d).\n", n); } } POSIX Standard Library v L’I/O UNIX si può effettuare interamente attraverso solo 5 funzioni Ø open, read, write, lseek, close v Tale tipologia di accesso Ø Fa parte di POSIX e della Single UNIX Specification ma non di ISO C Ø Si indica normalmente con il termine di “unbuffered I/O” nel senso che ciascuna operazione di read o write corrisponde a una system call al kernel System call open () v Nel kernel UNIX un "file descriptor" è un intero non negativo v Per convenzione (anche nella shell) Ø Standard input = descrittore 0 = STDIN_FILENO Ø Standard output = descrittore 1 = STDOUT_FILENO Ø Standard error = descrittore 2 = STDERR_FILENO v Tali descrittori sono definiti nel file di header unistd.h System call open () #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> int open (const char *path, int flags); int open (const char *path, int flags, mode_t mode); v Apre un file definendone i permessi v Valori di ritorno Ø Il descrittore del file in caso di successo Ø Il valore -1 in caso di errore System call open () v Può avere 2 oppure 3 parametri Ø Il parametro mode è opzionale v Path indica il file da aprire v Flag ha molteplici opzioni Ø Si ottiene mediante l’OR bi-a-bit di costanti presenti nel file di header fcntl.h Ø Una delle tre seguenti costanti è obbligatoria ● O_RDONLY ● O_WRONLY ● O_RDWR open for read-only access open for write-only access open for read-write access System call open () Ø Le seguenti costanti sono invece opzionali ● O_CREAT ● O_EXCL ● O_TRUNC ● O_APPEND ● O_SYNC ● ... crea il file se non esiste errore se O_CREAT è settato e il file esiste rimuove il contenuto del file appende al file ogni write attende l’operazioni di scrittura fisica sia terminata prima di proseguire System call open () v Mode specifica i diritti di accesso Ø S_I[RWX]USR Ø S_I[RWX]GRP Ø S_I[RWX]OTH rwx --- ----- rwx ----- --- rwx v Osservazione Ø I permessi con cui viene effettivamente creato un file sono modificati dall’umask dell’utente proprietario del processo ● mode & (~umask) System call read () #include <sys/types.h> #include <unistd.h> int read (int fd, void *buf, size_t nbytes); v Legge dal file fd un numero di byte uguale a nbytes, memorizzandoli in buf v Valori di ritorno Ø Il numero di byte letti in caso di successo Ø Il valore -1 in caso di errore Ø Il valore 0 in caso di EOF System call read () #include <sys/types.h> #include <unistd.h> int read (int fd, void *buf, size_t nbytes); v Il valore ritornato è inferiore a nbytes Ø Se la fine del file viene raggiunta prima di nbytes byte Ø Se la pipe da cui si sta leggendo non contiene nbytes bytes System call write () #include <sys/types.h> #include <unistd.h> int write (int fd, void *buf, size_t nbytes); v Scrive nbytes byte di buf nel file di descrittore fd v Valori di ritorno Ø Il numero di byte scritti in caso di successo, cioè normalmente nbytes Ø Il valore -1 in caso di errore System call write () #include <sys/types.h> #include <unistd.h> int write (int fd, void *buf, size_t nbytes); v Osservazione Ø write scrive sui buffer di sistema, non sul disco ● fd = open (file, O_WRONLY | O_SYNC); Ø O_SYNC forza la sync dei buffer, ma solo sul file sytem ext2 System call close () #include <unistd.h> int close (int fd); v Valori di ritorno Ø Il valore 0 in caso di successo Ø Il valore -1 in caso di errore v Tutti i file sono chiusi automaticamente quando il processo termina Un esempio di R/W ... #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #define BUFFSIZE 4096 ... int nR, nW, fdR, fdW; char buf[BUFFSIZE]; fdR = open (argv[1], O_RDONLY); fdW = open (argv[2], O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fdR==(-1) || fdW==(-1)) { fprintf (stdout, “Error Opening a File.\n“); exit (1); } Un esempio di R/W while ((nR = read (fdR, buf, BUFFSIZE)) > 0) { nW = write (fdW, buf, nR); if (nR != nW) fprintf (stderr, "Error: Read %d, Write %d).\n", nR, nW); } if (nW < 0) fprintf (stderr, "Write Error.\n"); close (fdR); close (fdW); exit(0); }