Apertura - Lettura
Per aprire e leggere un file possiamo fare in questo modo :
int fd = open("foo.txt", O_RDONLY);
char buffer[512];
ssize_t bytes_read = read(fd, buffer, 512);
close(fd);
printf("Read %zd : %s\n", bytes_read, buffer);- apertura del file con
open(...)restituisce un file descriptor per le operazioni future - la lettura con
read(...)restituisce il numero effettivo di byte letti - per i flag come
O_RDONLYbisogna includere anche#include <fcntl.h>e abbiamo :O_WRONLY: apre in modalità scritturaO_CREAT: crea il file se non esisteO_TRUNC: se il file esiste, tronca il contenuto a dimensione 0- si possono usare insieme separandoli da
|
Come parametro la call open() prende anche i permessi che verranno dati dal file creato se non esistente, per esempio 0670 :
0: indica a C che stiamo usando base 87: 4 (read) + 2 (write) + 1 (execute) al owner4: 4 (read) al gruppo0: nessun permesso a gli altri utenti
Siccome queste system call comunicano con il disco, possono ritornare degli errori (return -1), impostando una variabile globale di sistema errno con un errore specifico tra cui :
ENOENT: file does not existEBADF: bad file descriptor
Posizionamento seek
int fd = open("foo.txt", O_RDONLY);
lseek(fd, 128, SEEK_CUR); // POSIZIONAMENTO SEEKAttraverso lseek(fd, 128, SEEK_CUR) viene spostata la posizione corrente nel file :
- sposta il puntatore del file di 128 byte in avanti dalla posizione corrente nel file
- con
SEEK_CURsi indica di considerare la posizione corrente
Scrittura
Per poter scrivere in un file possiamo seguire il seguente esempio :
int fd = open("foo.txt", O_WRONLY | O_CREAT | O_TRUNC);
char buf[] = "Fratmmm!";
write(fd, buf, strlen(buf)); // SCRITTURA FILE
close(fd);che sovrascriverà il file esistente foot.txt (per O_TRUC) con “Fratmmm!”, oppure creerà il file foo.txt con quel contenuto se non esiste.
Altre operazioni fu file in UNIX
unlink("foo.txt"): rimuovere filerename("foo.txt", "bar.txt")chmod("foo.txt", 0755): cambio permessi filechown("foo.txt", uid, gid): cambio proprietà file
Scriviamo ora una funzione utility che ci permetta di leggere una riga da un file fino a \n o EOF (end-of-file) :
ssize_t read_line(int fd, char *buffer, ssize_t max_size) {
char c;
ssize_t read_size = 0;
// leggiamo fino al massimo
while (read_size < max_size - 1) {
ssize_t byte_read = read(fd, &c, 1); // leggi 1 solo carattere
if (byte_read == 0) { // sono arrivato a EOF
break;
}
buffer[read_size++] = c;
if (c == '\n') {
break;
}
}
buffer[read_size] = '\0';
return read_size;
}Consideriamo ora un esempio che ci permetta di vedere che è possibile scrivere anche roba binaria (diretta nel file come numeri) :
- Scrittura :
int file_fd;
char buffer[BUFFER_SIZE];
// 1. Aprire il file foo.txt e, se non esiste, crearlo.
file_fd = open(FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (file_fd < 0) {
perror("Errore nell'aprire il file");
return 1;
}
// 2. Scrive un intero in formato binario.
int my_int_bin = 42; // Intero da scrivere in formato binario
write(file_fd, &my_int_bin, sizeof(my_int_bin)); // Scrittura binaria
// 3. Scrive un intero in formato leggibile.
int my_int_text = 43; // Intero da scrivere in formato leggibile
sprintf(buffer, "%d\n", my_int_text);
int my_int_string_len = strlen(buffer);
write(file_fd, buffer, my_int_string_len); // Scrittura testuale
// 4. Scrive un float in formato binario.
float my_float_bin = 3.14f; // Float da scrivere in formato binario
write(file_fd, &my_float_bin, sizeof(my_float_bin)); // Scrittura binaria
// 5. Scrive un float in formato leggibile.
float my_float_text = 2.71f; // Float da scrivere in formato leggibile
sprintf(buffer, "%.2f\n", my_float_text);
int my_float_string_len = strlen(buffer);
write(file_fd, buffer, my_float_string_len); // Scrittura testuale
// 6. Scrive una stringa in formato leggibile.
const char *my_string_text = "Hello Text"; // Stringa da scrivere
sprintf(buffer, "%s\n", my_string_text);
write(file_fd, buffer, strlen(buffer)); // Scrittura testuale
// 7. Scrive una stringa più un numero in formato leggibile.
const char *message = "My favorite number is"; // Messaggio da scrivere
int favorite_number = 7; // Numero associato al messaggio
// Formatta il messaggio e il numero in una stringa leggibile
sprintf(buffer, "%s %d\n", message, favorite_number);
// Scrive il contenuto formattato nel file
write(file_fd, buffer, strlen(buffer));
// 8. Chiude il file dopo la scrittura.
close(file_fd);- Lettura :
// 9. Riapre il file per la lettura.
file_fd = open(FILENAME, O_RDONLY);
if (file_fd < 0) {
perror("Errore nell'aprire il file per lettura");
return 1;
}
// 10. Legge un intero in formato binario.
int read_int_bin;
read(file_fd, &read_int_bin, sizeof(read_int_bin)); // Lettura binaria
printf("Intero letto (binario): %d\n", read_int_bin);
// 11. Legge un intero in formato leggibile. Ma devo ricordare quanti byte ho scritto prima!
read(file_fd, buffer, my_int_string_len);
int read_int_text = atoi(buffer); // Conversione da stringa a intero
printf("Intero letto (testuale): %d\n", read_int_text);
// 12. Legge un float in formato binario.
float read_float_bin;
read(file_fd, &read_float_bin, sizeof(read_float_bin)); // Lettura binaria
printf("Float letto (binario): %.2f\n", read_float_bin);
// 13. Legge un float in formato leggibile. Ancora, devo ricordare quanti byte ho scritto prima!
read(file_fd, buffer, my_float_string_len);
float read_float_text = atof(buffer); // Conversione da stringa a float
printf("Float letto (testuale): %.2f\n", read_float_text);
// 14. Legge il resto del file, una riga alla volta fino alla fine del file (UTILIZZO FUNZIONE DI UTILTY CREATA PRIMA)
while (read_line(file_fd, buffer, BUFFER_SIZE) > 0) {
printf("Resto del file. Riga letta: %s", buffer);
}
// 15. Chiude il file.
close(file_fd);Lettura e Scrittura file con libreria standard di C e non POSIX
/*
* ---------------------------------------------------------------------
* 16. Esempio NON POSIX puro: usare fdopen() per scrivere e leggere
* in modo semplice tramite stdio (fprintf, fgets, ecc.)
* ---------------------------------------------------------------------
*
* Questo esempio mostra come il C possa essere molto più comodo quando
* si rinuncia al POSIX "low-level" e si passa all'I/O bufferizzato
* della libreria standard: FILE*, fprintf(), fgets().
*
* Si noti che fdopen() È POSIX, ma fprintf/fgets sono funzioni stdio.
* Questo approccio NON è più POSIX puro, ma spesso è più pratico.
*/
printf("\n--- Esempio alternativo: scrittura e lettura comoda (stdio) ---\n");
// Usiamo un file diverso per non sovrascrivere l'altro
const char *FILENAME_ALT = "foo_alt.txt";
// Apertura comoda in scrittura usando fopen() (stdio, NON POSIX puro)
FILE *fw = fopen(FILENAME_ALT, "w");
if (!fw) {
perror("Errore nell'aprire foo_alt.txt per scrittura");
return 1;
}
// Scrittura molto più semplice grazie a fprintf()
fprintf(fw, "Ciao, questa è una riga scritta in modo semplice!\n");
fprintf(fw, "Scrivo un numero: %d\n", 123);
fprintf(fw, "Scrivo un float: %.2f\n", 3.14);
fprintf(fw, "Scrivo anche più righe.\n");
fprintf(fw, "Tutto senza preoccuparmi di quanti byte scrivo.\n");
fclose(fw); // Chiude il FILE* (stdio)
// Ora leggiamo lo stesso file usando fdopen() + fgets()
int fd_alt = open(FILENAME_ALT, O_RDONLY);
if (fd_alt < 0) {
perror("Errore nell'aprire foo_alt.txt per lettura");
return 1;
}
// Convertiamo il file descriptor in FILE*
FILE *fr = fdopen(fd_alt, "r");
if (!fr) {
perror("Errore in fdopen() su foo_alt.txt");
close(fd_alt); // In caso di errore va chiuso a mano
return 1;
}
printf("\n--- Lettura da foo_alt.txt tramite fgets() ---\n");
// Lettura semplice con fgets()
while (fgets(buffer, BUFFER_SIZE, fr)) {
printf("fgets ha letto: %s", buffer);
}
// Chiude FILE* (che chiude automaticamente anche il file descriptor)
fclose(fr);
/*
* Nota: esiste anche getline(), che può leggere righe di qualunque
* lunghezza e gestisce da sola la memoria del buffer.
* Tuttavia getline() NON è POSIX, è GNU/BSD, quindi non lo includiamo.
*/Esempio copy file

