• Aucun résultat trouvé

fopen : ouverture du fichier

Dans le document Apprenez à programmer en C ! (Page 171-175)

Dans le chapitre sur les chaînes, nous nous sommes servis des prototypes des fonctions comme d'un « mode d'emploi ». C'est comme ça que les programmeurs font en général : ils lisent le prototype et comprennent comment ils doivent utiliser la fonction.

Je reconnais néanmoins que l'on a toujours besoin de quelques petites explications à côté quand même ! Voyons justement le prototype de la fonction fopen :

Code : C

FILE* fopen(const char* nomDuFichier, const char* modeOuverture);

Cette fonction attend deux paramètres : le nom du fichier à ouvrir ;

le mode d'ouverture du fichier, c'est-à-dire une indication qui mentionne ce que vous voulez faire : seulement écrire dans le fichier, seulement le lire, ou les deux à la fois.

Cette fonction renvoie… un pointeur sur FILE ! C'est un pointeur sur une structure de type FILE. Cette structure est définie dans stdio.h. Vous pouvez ouvrir ce fichier pour voir de quoi est constitué le type FILE, mais ça n'a aucun intérêt en ce qui nous concerne.

Pourquoi le nom de la structure est-il tout en majuscules (FILE) ? Je croyais que les noms tout en majuscules étaient réservés aux constantes et aux define ?

Cette « règle », c'est moi qui me la suis fixée (et nombre d'autres programmeurs suivent la même, d'ailleurs). Ça n'a jamais été une obligation. Force est de croire que ceux qui ont programmé stdio ne suivaient pas exactement les mêmes règles !

Cela ne doit pas vous perturber pour autant. Vous verrez d'ailleurs que les bibliothèques que nous étudierons ensuite respectent les mêmes règles que moi, à savoir ici mettre juste la première lettre d'une structure en majuscule.

Revenons à notre fonction fopen. Elle renvoie un FILE*. Il est extrêmement important de récupérer ce pointeur pour pouvoir ensuite lire et écrire dans le fichier.

Nous allons donc créer un pointeur de FILE au début de notre fonction (par exemple la fonction main) : Code : C

int main(int argc, char *argv[]) { FILE* fichier = NULL;

return 0;

}

Le pointeur est initialisé à NULL dès le début. Je vous rappelle que c'est une règle fondamentale que d'initialiser ses pointeurs à NULL dès le début si on n'a pas d'autre valeur à leur donner. Si vous ne le faites pas, vous augmentez considérablement le risque d'erreur par la suite.

Vous noterez qu'il n'est pas nécessaire d'écrire struct FILE* fichier = NULL. Les créateurs de stdio ont donc fait un typedef comme je vous ai appris à le faire il n'y a pas longtemps.

Notez que la forme de la structure peut changer d'un OS à l'autre (elle ne contient pas forcément les mêmes sous-variables partout). Pour cette raison, on ne modifiera jamais le contenu d'un FILE directement (on ne fera pas fichier.element par exemple). On passera par des fonctions qui manipulent le FILE à notre place.

Maintenant, nous allons appeler la fonction fopen et récupérer la valeur qu'elle renvoie dans le pointeur fichier. Mais avant ça, il faut que je vous explique comment se servir du second paramètre, le paramètre modeOuverture. En effet, il y a un code à envoyer qui indiquera à l'ordinateur si vous ouvrez le fichier en mode de lecture seule, d'écriture seule, ou des deux à la fois.

Voici les modes d'ouverture possibles.

"r" : lecture seule. Vous pourrez lire le contenu du fichier, mais pas y écrire. Le fichier doit avoir été créé au préalable.

"w" : écriture seule. Vous pourrez écrire dans le fichier, mais pas lire son contenu. Si le fichier n'existe pas, il sera créé.

"a" : mode d'ajout. Vous écrirez dans le fichier, en partant de la fin du fichier. Vous ajouterez donc du texte à la fin du fichier. Si le fichier n'existe pas, il sera créé.

"r+" : lecture et écriture. Vous pourrez lire et écrire dans le fichier. Le fichier doit avoir été créé au préalable.

"w+" : lecture et écriture, avec suppression du contenu au préalable. Le fichier est donc d'abord vidé de son contenu,

vous pouvez y écrire, et le lire ensuite. Si le fichier n'existe pas, il sera créé.

"a+" : ajout en lecture / écriture à la fin. Vous écrivez et lisez du texte à partir de la fin du fichier. Si le fichier n'existe pas, il sera créé.

Pour information, je ne vous ai présenté qu'une partie des modes d'ouverture. Il y en a le double, en réalité ! Pour chaque mode qu'on a vu là, si vous ajoutez un "b" après le premier caractère ("rb", "wb", "ab", "rb+", "wb+", "ab+"), alors le fichier est ouvert en mode binaire. C'est un mode un peu particulier que nous ne verrons pas ici. En fait, le mode texte est fait pour stocker… du texte comme le nom l'indique (uniquement des caractères affichables), tandis que le mode binaire permet de stocker… des informations octet par octet (des nombres, principalement). C'est sensiblement différent.

Le fonctionnement est de toute façon quasiment le même que celui que nous allons voir ici.

Personnellement, j'utilise souvent "r" (lecture), "w" (écriture) et "r+" (lecture et écriture). Le mode "w+" est un peu

dangereux parce qu'il vide de suite le contenu du fichier, sans demande de confirmation. Il ne doit être utilisé que si vous voulez d'abord réinitialiser le fichier.

Le mode d'ajout ("a") peut être utile dans certains cas, si vous voulez seulement ajouter des informations à la fin du fichier.

Si vous avez juste l'intention de lire un fichier, il est conseillé de mettre "r". Certes, le mode "r+" aurait fonctionné lui aussi, mais en mettant "r" vous vous assurez que le fichier ne pourra pas être modifié, ce qui est en quelque sorte une sécurité.

Si vous écrivez une fonction chargerNiveau (pour charger le niveau d'un jeu, par exemple), le mode "r" suffit. Si vous écrivez une fonction enregistrerNiveau, le mode "w" sera alors adapté.

Le code suivant ouvre le fichier test.txt en mode "r+" (lecture / écriture) : Code : C

int main(int argc, char *argv[]) { FILE* fichier = NULL;

fichier = fopen("test.txt", "r+");

return 0;

}

Le pointeur fichier devient alors un pointeur sur test.txt.

Où doit être situé test.txt ?

Il doit être situé dans le même dossier que votre exécutable (.exe).

Pour les besoins de ce chapitre, créez un fichier test.txt comme moi dans le même dossier que le .exe (fig. suivante).

Comme vous le voyez, je travaille actuellement avec l'IDE Code::Blocks, ce qui explique la présence d'un fichier de projet .cbp (au lieu de .sln, si vous avez Visual C++ par exemple). Bref, ce qui compte c'est de bien voir que mon programme

(tests.exe) est situé dans le même dossier que le fichier dans lequel on va lire et écrire (test.txt).

Le fichier doit-il être de type .txt ?

Non. C'est vous qui choisissez l'extension lorsque vous ouvrez le fichier. Vous pouvez très bien inventer votre propre format de fichier .niveau pour enregistrer les niveaux de vos jeux par exemple.

Le fichier doit-il être obligatoirement dans le même répertoire que l'exécutable ?

Non plus. Il peut être dans un sous-dossier : Code : C

fichier = fopen("dossier/test.txt", "r+");

Ici, le fichier test.txt est dans un sous-dossier appelé dossier. Cette méthode, que l'on appelle chemin relatif est plus pratique. Comme ça, cela fonctionnera peu importe l'endroit où est installé votre programme.

Il est aussi possible d'ouvrir un autre fichier n'importe où ailleurs sur le disque dur. Dans ce cas, il faut écrire le chemin complet (ce qu'on appelle le chemin absolu) :

Code : C

fichier = fopen("C:\Program Files\Notepad++\readme.txt", "r+");

Ce code ouvre le fichier readme.txt situé dans C:\Program Files\Notepad++.

J'ai dû mettre deux antislashs \ à chaque fois comme vous l'avez remarqué. En effet, si j'en avais écrit un seul, votre ordinateur aurait cru que vous essayiez d'insérer un symbole spécial comme \n ou \t. Pour écrire un antislash dans une chaîne, il faut donc l'écrire deux fois ! Votre ordinateur comprend alors que c'est bien le symbole \ que vous vouliez utiliser.

Le défaut des chemins absolus, c'est qu'ils ne fonctionnent que sur un OS précis. Ce n'est pas une solution portable, donc. Si vous aviez été sous Linux, vous auriez dû écrire un chemin à-la-linux, tel que :

Code : C

fichier = fopen("/home/mateo/dossier/readme.txt", "r+");

Je vous recommande donc d'utiliser des chemins relatifs plutôt que des chemins absolus. N'utilisez les chemins absolus que si votre programme est fait pour un OS précis et doit modifier un fichier précis quelque part sur votre disque dur.

Dans le document Apprenez à programmer en C ! (Page 171-175)

Documents relatifs