Gestion des dossiers et des fichiers en C avec la GLib
Date de publication : Non définie
Par
Julian Ibarz (home)
Nous apercevons dans beaucoup de forums des questions dont la plus posée est : "Comment explorer un dossier ?". La GLib propose une solution simple au moyen de quelques fonctions, profitons-en !
I. Exploration d'un dossier
II. Gestion de la portabilité
III. Gestion multi-utilisateur
IV. Gestion des erreurs
V. Remerciements
VI. Références
I. Exploration d'un dossier
Avant toute chose, il faut commencer par obtenir un descripteur sur le dossier,
à la manière d'un fichier, grâce à la fonction :
GDir* g_dir_open(const gchar *path, guint flags, GError **error);
|
-
path est la chaîne représentant le chemin. Par exemple sous windows : "c:\\windows".
-
flags n'est pour l'instant pas utilisé par la GLib. Celle-ci préconise de le mettre à 0.
-
error vous permet de récupérer les erreurs de runtime.
Pour fermer le dossier après son exploration, on utilisera :
void g_dir_close (GDir* dir);
|
Pour connaître les fichiers ou dossiers contenu dans notre dossier, on utilise :
G_CONST_RETURN gchar* g_dir_read_name(GDir* dir);
|
Ceci renvoie une chaîne de caractère représentant un fichier contenu dans le dossier. Par exemple votre dossier c:\moi\cours contient un fichier fichier.txt et bien si vous faîtes :
GDir* monDossier=g_dir_open("c:\\moi\\cours", 0, NULL);
G_CONST_RETURN gchar* file=g_dir_read_name(monDossier);
|
file sera bien sûr égal à "fichier.txt". Si vous rappelez la fonction, elle vous renverra un autre fichier contenu dans le dossier.
 |
Notez que "." et ".." qui représentent respectivement le dossier actuel et le dossier parent sont supprimés par la GLib. |
 |
L'ordre dans lequel les fichiers sont listés dépend du système.
|
Cette fonction nous dit quand s'arrêter car lorsqu'elle nous a renvoyé tous les fichiers contenus dans le dossier, elle renvoie NULL. Pour connaître tous
les fichiers d'un dossier, il vous suffit donc de faire une boucle et de mettre comme condition d'arrêt le retour NULL :
GDir* monDossier=g_dir_open("c:\\moi\\cours", 0, NULL);
G_CONST_RETURN gchar* file g_dir_read_name(monDossier);
while(file != NULL)
{
printf("%s\n",file);
file = g_dir_read_name(monDossier);
}
|
Si ça vous prend de vouloir recommencer l'exploration d'un dossier depuis le début, utilisez :
g_dir_rewind(monDossier);
|
Le prototype de la fonction est bien sûr (vous l'avez deviné) :
void g_dir_rewind(GDir *dir);
|
Maintenant, imaginons que vous vouliez explorer un dossier et ses sous-dossiers. Il vous faudra utiliser cette fonction :
gboolean g_file_test (const gchar *filename,
GFileTest test);
|
- filename l'adresse absolue ou relative (par rapport au dossier courant) du fichier à tester.
- test le test à effectuer.
Vous mettrez pour test la valeur
G_FILE_TEST_IS_DIR. Ainsi si cette fonction renvoie
TRUE, vous saurez que le fichier est en fait un dossier et vous n'aurez qu'à rappeler
récursivement votre fonction d'exploration
de dossier pour explorer ce dossier. Si vous voulez connaître d'autres valeurs
possibles pour cet argument, je vous invite à lire la
documentation officielle.
Pour connaître le dossier courant, rien de plus simple :
gchar* g_get_current_dir(void);
|
 |
Ne pas oublier de désallouer la chaîne renvoyée. De manière générale (sauf exception contraire),
tout return de type gchar* doit être désalloué avec g_free.
Par contre les return de type G_CONST_RETURN ne doivent surtout pas être désalloués.
|
Ainsi si g_get_current_dir me dit que le dossier courant est c:\moi et que vous voulez
savoir si c:\moi\cours\fichier.txt est un dossier. Vous aurez plusieurs choix possibles :
g_file_test("cours\\fichier.txt",G_FILE_TEST_IS_DIR);
g_file_test("c:\\moi\\cours\\fichier.txt",G_FILE_TEST_IS_DIR);
|
II. Gestion de la portabilité
La GLib fournit deux macros pour un peu plus de compatibilité.
Ceux qui s'intéressent à cela savent que sous windows les séparations
entre les dossiers constituant un chemin est le caractère '\', par exemple
c:\windows\system. Sous linux c'est le caractère '/', par exemple /usr/lib.
Lorsque vous constituez des chemins, utilisez les macros G_SEARCHPATH_SEPARATOR
(sous windows, le caractère '\') et G_SEARCHPATH_SEPARATOR_S (sous windows, la chaîne "\").
 |
Notez bien la notation standard que j'utilise : un caractère (de type C char) est entouré de ''
tandis qu'une chaîne (de type C char*) est entourée de "" ; ce qui n'est vraiment pas pareil. Si vous ne comprenez pas la nuance, je vous
suggère de revoir votre cours préféré de C ou d'aller voir l'article sur les chaînes de caractère.
|
Il y a aussi des fonctions qu'on cherche partout et qui sont en fait sous notre nez
(dans une autre rubrique de la GLib intitulée Miscellaneous Utility Functions...) comme celle-ci :
gchar* g_build_filename(const gchar* first_element,...);
|
Ainsi, si l'on tape :
gchar* file=g_build_filename("c:","temp","bou.txt",NULL);
g_free(file);
|
Et notre belle fonction produit le résultat suivant : "c:\\temp\\bou.txt" qui s'affiche comme ceci :
Ce qui est bien le résultat escompté... Magnifique non ?
Et si on veut contrôler le séparateur (le caractère '\\'), on utilise la fonction suivante :
gchar* g_build_path(const gchar *separator, const gchar *first_element, ...);
|
Un exemple pour comprendre :
g_build_path("#","c:","temp","bou.txt",NULL);
|
Ce qui produira :
Et la fonction est gentille en plus parce que si l'on tape :
g_build_filename("c:","","temp","bou.txt",NULL);
|
La fonction ne produira pas c:\\\temp\bou.txt mais le joli résultat
de tout à l'heure ou si l'on a oublié que la GLib mettait les séparateurs
automatiquement, par exemple si on écrit :
g_build_path("#","c:","#","temp","#","bou.txt",NULL);
|
Et bien notre fonction ne génèrera pas :
Mais reconnaîtra qu'on a inséré la chaîne de séparation par inadvertance
et les supprimera ; on aura donc comme résultat :
C'est sympa tout de même.
Une autre fonction utile :
gchar* g_path_get_basename(const gchar *file_name);
|
On donne un chemin absolu et on nous renvoie le nom du fichier.
Par exemple si on envoie "c:\\temp\\bou.txt", et bien on nous renvoie "bou.txt".
Pratique... Ne pas oublier de désallouer la chaîne qu'on nous renvoie !
Ensuite pour savoir si l'on a un chemin absolu ou non :
gboolean g_path_is_absolute(const gchar *file_name);
|
Si on envoie "c:\\temp\\bou.txt", on nous répond TRUE,
si c'est "bou.txt", c'est FALSE.
Et le petit gadget de la semaine :
G_CONST_RETURN gchar* g_path_skip_root(const gchar *file_name);
|
On envoie "c:\\temp\\bou.txt" et on nous renvoie "temp\\bou.txt".
Bref on supprime la racine.
Sous un UNIX la fonction supprimera le premier slash.
III. Gestion multi-utilisateur
Il peut arriver qu'on veuille stocker des fichiers dans le dossier Mes Documents ou
si l'on est linuxien home
qui sous windows est pour moi : c:\Document And Settings\Julian ;
et qui sous linux est /home/julian. Et bien pour savoir :
G_CONST_RETURN gchar* g_get_home_dir(void);
|
Cela permet de configurer votre programme différemment pour chaque
utilisateur sans passer par une boîte de dialogue pour choisir sa configuration.
Et si on veut stocker des fichiers temporaires dans le dossier
des fichiers temporaires (ce qui est légitime ;-) :
G_CONST_RETURN gchar* g_get_tmp_dir(void);
|
Allez, si vous voulez savoir comment vous vous appelez (on ne sait jamais, ça peut servir ;) :
G_CONST_RETURN gchar* g_get_user_name(void);
|
Il me renvoie Julian. Ensuite pour savoir le login de l'utilisateur courant :
G_CONST_RETURN gchar* g_get_real_name(void);
|
Il me renvoie aussi Julian mais sous un UNIX la première fonction
m'aurait renvoyée Julian Ibarz et la dernière julian...
IV. Gestion des erreurs
Le domaine d'erreur est G_FILE_ERROR, voici l'énumération :
typedef enum
{
G_FILE_ERROR_EXIST,
G_FILE_ERROR_ISDIR,
G_FILE_ERROR_ACCES,
G_FILE_ERROR_NAMETOOLONG,
G_FILE_ERROR_NOENT,
G_FILE_ERROR_NOTDIR,
G_FILE_ERROR_NXIO,
G_FILE_ERROR_NODEV,
G_FILE_ERROR_ROFS,
G_FILE_ERROR_TXTBSY,
G_FILE_ERROR_FAULT,
G_FILE_ERROR_LOOP,
G_FILE_ERROR_NOSPC,
G_FILE_ERROR_NOMEM,
G_FILE_ERROR_MFILE,
G_FILE_ERROR_NFILE,
G_FILE_ERROR_BADF,
G_FILE_ERROR_INVAL,
G_FILE_ERROR_PIPE,
G_FILE_ERROR_AGAIN,
G_FILE_ERROR_INTR,
G_FILE_ERROR_IO,
G_FILE_ERROR_PERM,
G_FILE_ERROR_FAILED
} GFileError;
|
Et la documentation :
-
G_FILE_ERROR_EXIST Opération non permise : seulement le propriétaire du
fichier (ou une autre personne) ou un processus avec les droits appropriés peut effectuer l'opération.
-
G_FILE_ERROR_ISDIR Le fichier est un dossier ;
vous ne pouvez ouvrir un fichier en mode écriture, ou créer ou effacer
des liens (comprenez des fichiers : un dossier est un ensemble de "pointeurs",
à comprendre comme les pointeurs en C, qui contiennent l'adresse des fichiers
dans le disque dur).
-
G_FILE_ERROR_ACCES Permission refusée ; les attributs du
fichier ne permettent pas cette opération.
-
G_FILE_ERROR_NAMETOOLONG Nom de fichier trop long.
-
G_FILE_ERROR_NOENT Impossible de trouver le fichier ou le dossier.
Ceci est une erreur de fichier introuvable "This is a "file doesn't exist" error for ordinary files that are
referenced in contexts where they are expected to already exist.
-
G_FILE_ERROR_NOTDIR Un fichier qui n'est pas un dossier a
été donné quand un dossier est attendu.
-
G_FILE_ERROR_NXIO Matériel ou adresse introuvable.
Le système a essayé d'utiliser le matériel représenté par un
fichier que vous avez donné et il ne l'a pas trouvé
(pour les nons-unixens, dans le monde unix, le driver d'un matériel
dialogue avec le système à travers un banal fichier).
Cela peut dire que le fichier du matériel a été mal installé, ou que
le matériel physique est en train d'utiliser le fichier ou est mal connecté
à l'ordinateur.
-
G_FILE_ERROR_NODEV Ce fichier est sur un système de fichier qui ne supporte
pas le mapping.
-
G_FILE_ERROR_ROFS Le dossier contenant le nouveau lien ne peut
pas être modifié car il est sur un système de fichier en lecture seule.
-
G_FILE_ERROR_TXTBSY Fichier texte occupé.
-
G_FILE_ERROR_FAULT Vous pointez vers une mauvaise zone mémoire. La GLib ne sera
plus stable si ceci est retourné.
-
G_FILE_ERROR_LOOP Trop de niveau de liens symboliques ont été rencontrés
lors de la lecture du nom de fichier. Cela arrive quand il y a un cycle dans les
liens symboliques.
-
G_FILE_ERROR_NOSPC Plus d'espace disque ;
l'opération d'écriture dans un fichier a échouée
parce que le disque est plein.
-
G_FILE_ERROR_NOMEM Pas assez de mémoire. Le système ne peut
plus allouer assez de mémoire virtuelle parce que le disque dur est plein
(la mémoire virtuelle a le même rôle qu'une mémoire vive mais son lieu de stockage
est le disque dur ; d'où son adjectif virtuelle).
-
G_FILE_ERROR_MFILE Le processus courant a trop de fichiers
ouverts et ne peut plus en ouvrir d'autres.
Duplicate descriptors do count toward this limit.
-
G_FILE_ERROR_NFILE Il y a trop de fichiers ouverts en même temps dans le système.
-
G_FILE_ERROR_BADF Mauvais descripteur de fichier ; Par exemple, écriture ou lecture
sur un descripteur qui a été fermé ou lecture sur un descripteur qui est ouvert
seulement pour de l'écriture (ou vice versa).
-
G_FILE_ERROR_INVAL Argument invalide. Cette erreur est
utilisée pour indiquer différents problèmes qui ont pour origine
le passage d'un argument incorrect à une fonction de la librairie.
-
G_FILE_ERROR_PIPE Erreur UNIX seulement qui arrive si on utilise des tubes de communication.
Tube de communication cassé ;
Il n'y a aucun processus en lecture sur ce tube. Tous les fonctions de la librairie
qui retournent cette erreur génèrent aussi un signal SIGPIPE ; ce signal
termine le programme si ce dernier n'est pas bloqué ou récupéré.
Ainsi, votre programme ne verra jamais ce code d'erreur s'il ne bloque pas ou
ne récupère pas le signal SIGPIPE.
-
G_FILE_ERROR_AGAIN Ressource temporairement inaccessible ;
l'appel devrait marchait si vous essayez encore.
-
G_FILE_ERROR_INTR Appel de fonction interrompu ; un signal asynchrone
est arrivé et a arrêté l'appel de la fonction. Quand cela arrive, vous devriez
simplement rappeler la fonction.
-
G_FILE_ERROR_IO Erreur de Lecture/Écriture ;
généralement utilisé pour des erreurs de lecture ou d'écriture
physiques c'est-à-dire que le disque ou un autre matériel physique a rencontré une erreur.
-
G_FILE_ERROR_PERM Opération non permise : seulement le
propriétaire du fichier (ou une autre personne) ou un processus
avec les droits appropriés peut effectuer l'opération.
-
G_FILE_ERROR_FAILED Ne correspond pas à un code d'erreur UNIX
: ceci est le code d'erreur standard pour une "erreur de cause inconnue"
présent dans toutes les énumérations de code d'erreur d'un GError.
Utilisé si aucun autre code ne peut être appliqué.
 |
Notez que l'on peut recevoir deux codes d'erreur différents pour
une même erreur dans deux systèmes d'exploitation différents.
En effet, pour les systèmes UNIX, la GLib se base sur les codes
d'erreurs de la GNU C Library et à ceux de Microsoft sous Windows.
|
V. Remerciements
Je voudrais remercier
Gege2061 pour ses conseils et relectures.
VI. Références
Voici différents liens qui pourraient vous être utiles :


Copyright © 2008 Julian Ibarz. Aucune reproduction, même partielle, ne peut être faite
de ce site et de l'ensemble de son contenu : textes, documents, images, etc
sans l'autorisation expresse de l'auteur.
Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E
de dommages et intérêts.
Cette page est déposée à la
SACD.