Partie 2 - Fichiers¶
Support présentationIntroduction¶
Dans les systèmes Unix/Linux, un fichier est une simple séquence d’octets stockée sur un périphérique.
Le système ne connaît pas sa signification (texte, image, vidéo, binaire, base de données…).
C’est le programme qui interprète les octets.
Il existe cependant des standards de format (.png, .mp3, .wav…) permettant à différents programmes de lire un fichier de la même manière, mais rien n’est imposé par le système.
La commande file détermine le type de contenu.
Le principe fondamental d’Unix : « Tout est fichier ». Cela inclut :
fichiers classiques (texte, binaire, vidéo, …),
répertoires (
/home,/tmp, …),périphériques (clavier, disque, carte son…),
tubes (pipes),
sockets,
liens symboliques,
etc.
Tous ces objets peuvent être manipulés avec les mêmes primitives systèmes (open, read, write, close, …).
Sous Linux, les fichiers sont organisés sous forme de structure arborescente, commençant à la racine /.
La commande tree permet d’afficher l’arborescence d’un dossier :
$ tree -L 1 /
/
├── bin -> usr/bin
├── boot
├── dev
├── etc
├── home
├── lib -> usr/lib
├── lib32 -> usr/lib32
├── lib64 -> usr/lib64
├── libx32 -> usr/libx32
├── lost+found
├── media
├── mnt
├── opt
├── proc
├── root
├── run
├── sbin -> usr/sbin
├── snap
├── srv
├── sys
├── tmp
├── usr
└── var
23 directories, 0 files
Pour parcourir les dossiers, on distingue deux types de chemins :
- absolucommence à la racine
/: /home/user/file.txt/bin/bash
- absolucommence à la racine
- relatifdépend du répertoire courant :
./file.txt(où.représente le répertoire courant)../autre.txt(où..représente le répertoire parent)
Système de fichiers¶
Le système de fichiers (ext4, NTFS, FAT32…) est le logiciel responsable de l’organisation des fichiers sur le disque.
Il gère :
les inodes, répertoires et blocs disque,
les permissions et métadonnées,
l’accès efficace et sécurisé aux fichiers,
la cohérence des données (journalisation, verrouillage, …).
Il fait l’interface entre le matériel (disque physique) et le noyau.
Nous obtenons la chaîne suivante :
Disque physique <- système de fichiers <- inodes & répertoires <- noyau Linux <- descripteurs de fichiers <- votre programme
Lorsque votre programme veut lire un fichier, il appelle open(), le noyau associe le fichier à un descripteur de fichier (un int) puis le programme peut utiliser ce descripteur avec read(), write(), close(), …
Il existe de nombreux systèmes de fichiers, chacun ayant ses spécificités en termes de performances, fiabilité, compatibilité ou fonctionnalités.
Quelques exemples courants :
ext4 (Linux) - Le plus répandu sous Linux. - Rapide, fiable, avec journalisation. - Gère de très gros fichiers et volumes. - Limite de taille : fichier jusqu’à 16 To, partition jusqu’à 1 Eo.
NTFS (Windows) - Par défaut sur Windows modernes. - Supporte les droits d’accès avancés, la compression, le chiffrement. - Très bonne compatibilité Windows, mais écriture limitée sous Linux/macOS (mieux gérée avec des pilotes tiers).
FAT32 (Windows, ancien, universel) - Très compatible (clé USB, cartes SD, BIOS). - Mais limité : fichiers max 4 Go, partitions max 2 To. - Pas de journalisation → moins fiable en cas de coupure brutale.
exFAT (Microsoft, optimisé pour flash) - Successeur de FAT32, sans limite de 4 Go par fichier. - Très utilisé pour les clés USB, cartes SDXC, disques externes. - Supporté par Windows, macOS et Linux (via pilotes).
XFS (Linux) - Système journalisé hautes performances. - Optimisé pour les très gros fichiers et les serveurs de stockage. - Pas de réduction de taille de partition possible.
Btrfs (Linux) - Système moderne, orienté fonctionnalités avancées (snapshots, checksums, RAID intégré). - Encore considéré moins stable qu’ext4 dans certains contextes. - Bon candidat pour serveurs et systèmes exigeants.
APFS (macOS) - Système de fichiers par défaut sur macOS récent. - Optimisé SSD, snapshots intégrés, chiffrement natif. - Non compatible nativement avec Linux ou Windows.
Inodes¶
Un fichier est décrit par une structure interne : l”inode (index node) qui contient ses métadonnées :
type (fichier, répertoire, lien…),
taille (en octets),
droits d’accès (lecture/écriture/exécution),
propriétaire (UID) et groupe (GID),
dates (création, dernier accès, modification),
nombre de liens,
pointeurs vers les blocs disque.
La commande stat affiche les métadonnées :
$ echo "coucou" > mon_fichier.txt
$ stat mon_fichier.txt
Fichier : mon_fichier.txt
Taille : 7 Blocs : 8 Blocs d'E/S : 4096 fichier
Périphérique : fc01h/64513d Inœud : 17309649 Liens : 1
Accès : (0644/-rw-r--r--) UID : (1000/user) GID : (1000/user)
Accès : 2025-08-19 13:43:30.226795166 +0200
Modif. : 2025-08-19 13:43:30.227795178 +0200
Changt : 2025-08-19 13:43:30.227795178 +0200
Créé : 2025-08-19 13:43:30.226795166 +0200
$ file mon_fichier.txt
mon_fichier.txt: ASCII text
Taille logique vs physique¶
Chaque fichier occupe au minimum un bloc disque (souvent 4 Ko). La taille logique (octets de données) peut être bien plus petite que la place réellement allouée.
Dans l’exemple ci-dessus avec stat, le fichier ne contient que 7 octets, mais occupe un bloc entier (8 blocs de 512 octets, soit 4 Ko minimum).
Types de fichiers¶
On peut les voir avec ls -l, le premier caractère indique le type :
-: fichier régulierd: répertoire (directory)l: lien symbolique (symlink)c: périphérique caractère (terminal, clavier…)b: périphérique bloc (disque dur…)s: socketp: pipe nommé (FIFO)
Exemple :
$ ls -l /dev/null /bin/ls /
-rwxr-xr-x 1 root root 138216 févr. 8 2024 /bin/ls
crw-rw-rw- 1 root root 1, 3 août 18 09:33 /dev/null
...
drwxr-xr-x 169 root root 12288 août 18 10:08 etc
...
Droits des fichiers¶
ls -l affiche aussi, après le type, les droits/permissions sur les fichiers avec les r (read, droit de lecture), w (write, droit de modification), x (execute, droit d’execution) pour le propriétaire, puis le groupe puis les autres.
ainsi :
rwxr-xr-xindique que le propriétaire a les droits de lecture, écriture et execution et le groupe et les autres ont les droits de lecture et d’execution.
La commande chmod permet de changer ces droits.
La commande chown permet de changer le propriétaire et groupe.
Plus de détail dans le cours de bash.
Descripteurs de fichiers¶
Chaque processus possède une table des fichiers ouverts. Le noyau associe un entier (le descripteur) à une structure interne décrivant le fichier.
Trois descripteurs standards sont toujours ouverts au lancement :
0: entrée standard (stdin),1: sortie standard (stdout),2: sortie d’erreur (stderr).
Ce mécanisme permet les redirections :
$ ls > out.txt # redirige stdout vers un fichier
$ ls 2> err.txt # redirige stderr
$ sort < data.txt # lit sur stdin depuis un fichier
$ ls | grep ".c" # pipe : stdout de ls vers stdin de grep
Liens symboliques et physiques¶
Deux mécanismes Unix permettent de donner plusieurs noms à un fichier :
Lien physique (hard link) : un second nom pointant vers le même inode. Le fichier reste valide tant qu’au moins un lien existe.
Lien symbolique (soft link / symlink) : un raccourci vers un autre fichier. S’il est supprimé, le lien devient cassé.
Commandes :
ln fichier_cible lien # lien physique
ln -s fichier_cible lien # lien symbolique
Accès aux fichiers en C¶
En C sous Unix/Linux, il existe deux façons principales d’accéder aux fichiers :
Avec la bibliothèque standard du C (libc, ``<stdio.h>``) : fonctions de haut niveau, bufferisées en mémoire utilisateur, pratiques mais moins prévisibles.
Avec les appels système POSIX (``<unistd.h>``, ``<fcntl.h>``) : fonctions de bas niveau, non bufferisées, proches du noyau, utilisées en interne par la libc.
Note
La bufferisation stocke temporairement les données dans un tampon pour réduire les appels système et améliorer les performances.
Un équivalent serait d’attendre que le réservoir d’essence d’une voiture soit vide (ou presque vide) pour aller le remplir plutôt que d’aller faire le plein à chaque trajet.
Pour de nombreuses fonctions ci-dessous, la valeur de retour est 0 si tout c’est bien passé et -1 s’il y a une erreur qu’il faut mieux afficher avec perror.
Libc (I/O bufferisées)¶
La manipulation via la libc se fait avec la structure FILE (flux stream) qui encapsule un descripteur de fichier noyau, un tampon, les états EOF/erreur, la position logique, etc.
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 int main(void) {
5 FILE *f = fopen("data.txt", "w");
6 if (!f) {
7 perror("fopen");
8 exit(EXIT_FAILURE);
9 }
10 fprintf(f, "Hello bufferisé !\n");
11 fclose(f);
12 return 0;
13 }
fopen() et fclose() permettent d’ouvrir et fermer un flux FILE.
#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict mode);
int fclose(FILE *stream);
Paramètres
pathname: chemin du fichier.mode:"r": lecture"w": écriture (efface si existant)"a": ajout en fin"r+": lecture + écriture"b": mode binaire (ex :"rb","wb")
Retour
fopen: pointeurFILE*ouNULL(errno).fclose:0si succès,EOFsinon.
Pour les autres fonctions de la libc, voir les consignes dans les exercices, si vous avez un doute le man peut vous aider.
Appels système (I/O non bufferisées)¶
Les appels système donnent directement les descripteurs de fichiers et travaillent ensuite avec :
1#include <fcntl.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <errno.h>
7
8int main(void) {
9 int fd = open("data.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
10 if (fd == -1) {
11 perror("open");
12 exit(EXIT_FAILURE);
13 }
14
15 const char *msg = "Hello bas niveau !\n";
16 ssize_t n = write(fd, msg, strlen(msg));
17 if (n == -1) {
18 perror("write");
19 close(fd);
20 exit(EXIT_FAILURE);
21 }
22
23 close(fd);
24 return 0;
25}
open() Ouvre un fichier et renvoie un descripteur de fichier, close() ferme le descripteur de fichier.
#include <fcntl.h>
#include <sys/stat.h>
int open(const char *pathname, int flags, ... /* mode_t mode */);
Paramètres
pathname: chemin du fichier.flags: voir ci-dessousmode: requis siO_CREAT(droits initiaux, affectés parumask).
Flags courants :
O_RDONLY(lecture seule),O_WRONLY(écriture seule),O_RDWR(lecture+écriture)O_CREAT: créer si inexistant (nécessitemode)O_TRUNC: tronquer à 0 si existant (avec écriture)O_APPEND: ajout en finO_EXCL: échec si le fichier existe déjà (à combiner avecO_CREAT)O_CLOEXEC: ferme automatiquement le fd lors d’unexecve(sécurité)O_NONBLOCK: E/S non bloquantes (si pertinent)O_DIRECTORY: échouer sipathnamen’est pas un répertoire
Pour les autres fonctions POSIX, voir les consignes dans les exercices, si vous avez un doute le man peut vous aider.
Permissions et masque (umask)¶
Chaque fichier a des permissions Unix : lecture (r), écriture (w), exécution (x), définies pour utilisateur, groupe, autres.
Exemple : -rw-r--r-- = propriétaire lecture/écriture, autres lecture seule.
La fonction umask définit un masque par défaut qui supprime certains droits à la création.
#include <sys/stat.h>
umask(0022); // interdit l'écriture pour groupe/autres
int fd = open("fichier.txt", O_CREAT | O_WRONLY, 0666);
// droits effectifs : 0666 & ~0022 = 0644
Verrouillage de fichiers¶
Quand plusieurs processus écrivent dans le même fichier, il faut éviter les conflits. Deux mécanismes existent :
flock(fd, LOCK_EX): verrouillage simple (exclusif ou partagé)fcntl(fd, F_SETLK): verrouillage plus fin (plages de bytes)
Exemple simple avec flock :
#include <sys/file.h>
int fd = open("data.txt", O_WRONLY);
flock(fd, LOCK_EX); // verrou exclusif
write(fd, "Hello\n", 6);
flock(fd, LOCK_UN); // libère
close(fd);
Fichiers spéciaux¶
Sous Unix, certains fichiers n’ont pas de données réelles mais sont des interfaces système :
/dev/null: tout ce qui est écrit est jeté, lecture = EOF,/dev/urandom: générateur pseudo-aléatoire,/proc: expose des infos sur les processus et le noyau,/sys: interface avec les périphériques.
Exemple :
$ cat /dev/null
$ head -c 16 /dev/urandom | hexdump -C
$ cat /proc/cpuinfo
Exemple long de l’utilisation de stat¶
Ci-dessous, on crée un fichier vide avec touch, puis on affiche les métadonnées avec stat.
Ensuite on ajoute des données dans le fichier puis constate que la taille et la date de modification change, on modifie ensuite les permissions avec chmod.
Enfin, on crée un lien symbolique avec ln -s de salut vers coucou. C’est un raccourci, il pointe donc vers un autre fichier par son nom. Puis un lien physique de bonjour vers coucou. Quand coucou est supprimé, salut devient un lien mort. Le lien physique ajoute un nouveau nom à un même inode qui reste fonctionnel tant qu’un nom le référence.
$ touch coucou
$ stat coucou
Fichier : coucou
Taille : 0 Blocs : 0 Blocs d'E/S : 4096 fichier vide
Périphérique : fc01h/64513d Inœud : 17386826 Liens : 1
Accès : (0644/-rw-r--r--) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:10.187566033 +0200
Modif. : 2025-07-21 17:36:10.187566033 +0200
Changt : 2025-07-21 17:36:10.187566033 +0200
Créé : 2025-07-21 17:36:10.186566018 +0200
$ echo "salut" >> coucou
$ stat coucou
Fichier : coucou
Taille : 6 Blocs : 8 Blocs d'E/S : 4096 fichier
Périphérique : fc01h/64513d Inœud : 17386826 Liens : 1
Accès : (0644/-rw-r--r--) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:10.187566033 +0200
Modif. : 2025-07-21 17:36:26.285805213 +0200
Changt : 2025-07-21 17:36:26.285805213 +0200
Créé : 2025-07-21 17:36:10.186566018 +0200
$ chmod +x coucou
$ stat coucou
Fichier : coucou
Taille : 6 Blocs : 8 Blocs d'E/S : 4096 fichier
Périphérique : fc01h/64513d Inœud : 17386826 Liens : 1
Accès : (0755/-rwxr-xr-x) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:10.187566033 +0200
Modif. : 2025-07-21 17:36:26.285805213 +0200
Changt : 2025-07-21 17:36:40.146011146 +0200
Créé : 2025-07-21 17:36:10.186566018 +0200
$ ln -s coucou salut
$ stat coucou
Fichier : coucou
Taille : 6 Blocs : 8 Blocs d'E/S : 4096 fichier
Périphérique : fc01h/64513d Inœud : 17386826 Liens : 1
Accès : (0755/-rwxr-xr-x) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:10.187566033 +0200
Modif. : 2025-07-21 17:36:26.285805213 +0200
Changt : 2025-07-21 17:36:40.146011146 +0200
Créé : 2025-07-21 17:36:10.186566018 +0200
$ stat salut
Fichier : salut -> coucou
Taille : 6 Blocs : 0 Blocs d'E/S : 4096 lien symbolique
Périphérique : fc01h/64513d Inœud : 17387173 Liens : 1
Accès : (0777/lrwxrwxrwx) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:52.110188907 +0200
Modif. : 2025-07-21 17:36:52.109188892 +0200
Changt : 2025-07-21 17:36:52.109188892 +0200
Créé : 2025-07-21 17:36:52.109188892 +0200
$ ln coucou bonjour
$ stat coucou
Fichier : coucou
Taille : 6 Blocs : 8 Blocs d'E/S : 4096 fichier
Périphérique : fc01h/64513d Inœud : 17386826 Liens : 2
Accès : (0755/-rwxr-xr-x) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:10.187566033 +0200
Modif. : 2025-07-21 17:36:26.285805213 +0200
Changt : 2025-07-21 17:37:11.421475831 +0200
Créé : 2025-07-21 17:36:10.186566018 +0200
$ stat salut
Fichier : salut -> coucou
Taille : 6 Blocs : 0 Blocs d'E/S : 4096 lien symbolique
Périphérique : fc01h/64513d Inœud : 17387173 Liens : 1
Accès : (0777/lrwxrwxrwx) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:52.110188907 +0200
Modif. : 2025-07-21 17:36:52.109188892 +0200
Changt : 2025-07-21 17:36:52.109188892 +0200
Créé : 2025-07-21 17:36:52.109188892 +0200
$ stat bonjour
Fichier : bonjour
Taille : 6 Blocs : 8 Blocs d'E/S : 4096 fichier
Périphérique : fc01h/64513d Inœud : 17386826 Liens : 2
Accès : (0755/-rwxr-xr-x) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:10.187566033 +0200
Modif. : 2025-07-21 17:36:26.285805213 +0200
Changt : 2025-07-21 17:37:11.421475831 +0200
Créé : 2025-07-21 17:36:10.186566018 +0200
$ rm coucou
$ stat coucou
stat: impossible d'exécuter statx 'coucou': Aucun fichier ou dossier de ce nom
$ stat bonjour
Fichier : bonjour
Taille : 6 Blocs : 8 Blocs d'E/S : 4096 fichier
Périphérique : fc01h/64513d Inœud : 17386826 Liens : 1
Accès : (0755/-rwxr-xr-x) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:10.187566033 +0200
Modif. : 2025-07-21 17:36:26.285805213 +0200
Changt : 2025-07-21 17:37:29.461743875 +0200
Créé : 2025-07-21 17:36:10.186566018 +0200
$ stat salut
Fichier : salut -> coucou
Taille : 6 Blocs : 0 Blocs d'E/S : 4096 lien symbolique
Périphérique : fc01h/64513d Inœud : 17387173 Liens : 1
Accès : (0777/lrwxrwxrwx) UID : (675349/cgrelier) GID : (200367/optimist)
Accès : 2025-07-21 17:36:52.110188907 +0200
Modif. : 2025-07-21 17:36:52.109188892 +0200
Changt : 2025-07-21 17:36:52.109188892 +0200
Créé : 2025-07-21 17:36:52.109188892 +0200
$ cat salut
cat: salut: Aucun fichier ou dossier de ce nom