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 :

 
Sélectionnez

			GDir* g_dir_open(const gchar *path, guint flags, GError **error);

Si le dernier paramètre vous horrifie, allez voir l'article sur la gestion des erreurs en C avec la GLib.

  • 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 :

 
Sélectionnez

void g_dir_close (GDir* dir);

Pour connaître les fichiers ou dossiers contenu dans notre dossier, on utilise :

 
Sélectionnez
		
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 :

 
Sélectionnez

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 :

 
Sélectionnez

GDir* monDossier=g_dir_open("c:\\moi\\cours", 0, NULL);
G_CONST_RETURN gchar* file g_dir_read_name(monDossier);

// Affiche tous les fichiers et dossiers contenus dans monDossier sur la sortie standard
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 :

 
Sélectionnez

g_dir_rewind(monDossier);

Le prototype de la fonction est bien sûr (vous l'avez deviné) :

 
Sélectionnez

void g_dir_rewind(GDir *dir);

Maintenant, imaginons que vous vouliez explorer un dossier et ses sous-dossiers. Il vous faudra utiliser cette fonction :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

g_file_test("cours\\fichier.txt",G_FILE_TEST_IS_DIR); // Chemin relatif
g_file_test("c:\\moi\\cours\\fichier.txt",G_FILE_TEST_IS_DIR); // Chemin absolu

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 :

 
Sélectionnez

gchar* g_build_filename(const gchar* first_element,...);

Ainsi, si l'on tape :

 
Sélectionnez

gchar* file=g_build_filename("c:","temp","bou.txt",NULL); // le NULL pour dire : "Ca y est, on arrête !". Sinon madame la GLib continue...
g_free(file); // Et on n'oublie pas de désallouer !

Et notre belle fonction produit le résultat suivant : "c:\\temp\\bou.txt" qui s'affiche comme ceci :

 
Sélectionnez

c:\temp\bou.txt

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 :

 
Sélectionnez

gchar* g_build_path(const gchar *separator, const gchar *first_element, ...);

Un exemple pour comprendre :

 
Sélectionnez

g_build_path("#","c:","temp","bou.txt",NULL);

Ce qui produira :

 
Sélectionnez

c:#temp#bou.txt

Et la fonction est gentille en plus parce que si l'on tape :

 
Sélectionnez

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 :

 
Sélectionnez

g_build_path("#","c:","#","temp","#","bou.txt",NULL);

Et bien notre fonction ne génèrera pas :

 
Sélectionnez

c:###temp###bou.txt

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 :

 
Sélectionnez

c:#temp#bou.txt

C'est sympa tout de même.

Une autre fonction utile :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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 :

 
Sélectionnez

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

 
Sélectionnez

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

 
Sélectionnez

G_CONST_RETURN gchar* g_get_user_name(void);

Il me renvoie Julian. Ensuite pour savoir le login de l'utilisateur courant :

 
Sélectionnez

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 :

 
Sélectionnez

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 :