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);
}