Section 2 : Écrire dans un fichier
La façon la plus simple de d'ouvrir un fichier pour l'écriture est avec la fonction os.Create. Elle s'appelle de cette façon parce que si le fichier n'existe pas, alors le fichier va être créé avant de pouvoir y écrire. Si le fichier existe déjà, il sera tronqué, c'est-à-dire que sont contenu sera effacé et pour ensuite y écrire à partir du début. C'est comme ai on écrivait par-dessus le fichier existant.
Exemple simple d'écriture dans un fichier
La fonction a comme paramètre le nom du fichier
filenamedans lequel on doit écrire.On commence par création du nouveau fichier en utilisant la fonction
os.Createavec le nom de fichier fourni en argument. Cette fonction crée un nouveau fichier et si le fichier existe déjà, elle tronque le contenu du fichier. Le résultat de la fonctionos.Createcomprend deux variables. La première est un pointeur de de fichierfilequi est utilisée pour les opérations de fichier ultérieures et la seconde est une erreurerrqui aurait pu se produire.On vérifie ensuite s'il y a eu une erreur lors de la création du fichier. S'il y a eu une erreur (
errn'est pasnil), on logue l'erreur et termine immédiatement le programme en utilisantlog.Fatal(err).L'instruction
defer file.Close()fait en sorte quefile.Close()soit appelée juste avant que la fonctionsection2ane se termine, soit normalement ou via une erreur non traitée, afin de libérer les ressources du système (voir les détails plus bas).Ensuite, on utilise la fonction
file.WriteStringpour écrire une chaîne de caractères dans le fichier. Le comptage en octets du contenu écrit est stocké dansbytesWritten, et toute erreur pendant le processus est stockée danserr.Encore une fois, toute erreur lors de l'écriture dans le fichier est vérifiée et s'il y a eu une erreur, le programme enregistre l'erreur et se termine immédiatement.
Si l'écriture des bytes est réussie, le nombre de bytes écrits est enregistré dans le journal (
log).
Si on n'utilisait pas defer ici, et qu'on appelait Close à la fin de la fonction comme dans les exemples précédents, alors ça pourrait créer des problèmes. Quand on ouvre un fichier (ou toute autre resource), il faut s'assurer de la fermer, ou libérer, avant de quitter la fonction. Si on a un return avant de se rendre à la fin de la fonction, ou si on quitte à cause d'une erreur, comme avec log.Fatal ou avec une panique (une erreur grave au moment de l'exécution), alors le fichier, ou en général la resource, ne sera pas fermée, et ça pourrait causer des problèmes, comme des fuites de mémoires ou, dans notre cas, des données qui ne seraient pas enregistrées correctement dans le fichier ouvert. Si on n'utilise pas defer, il faudrait appeler file.Close() possiblement à plusieurs endroits, à chaque endroit où on pourrait potentiellement quitter la fonction. Dans certains cas, comme pour les paniques, elles pourraient arriver à des endroits imprévus, donc la resource pourrait ne jamais être correctement fermée ou libérée.
L'utilisation de defer file.Close() nous assure que le fichier sera fermé, peu importe la façon dont nous quittons la fonction. Dans les exemples précédents, puisque les fichiers étaient ouverts en lecture seule, le fichier n'était pas modifié, donc on ne pouvait pas perdre de données si le fichier n'était pas fermé correctement. Mais il est tout de même préférable d'utiliser defer dans tous les cas pour s'assurer d'une bonne gestion de la mémoire, pour ne pas conserver les contenu des fichiers en mémoire pour rien.
Exemple : écrire des données entrées par l'utilisateur dans un fichier
La fonction suivante demande des entrées à l'utilisateur et écrit ces entrées dans un fichier CSV en utilisant les opérations d'E/S de fichiers de la bibliothèque standard.
Voici un pas à pas de la fonction section2b:
La fonction
section2bcommence par déclarer une variablenAttemptsqui définit une limite au nombre de tentatives de lecture des entrées.Elle demande à l'utilisateur de saisir le nom du fichier dans lequel les données doivent être enregistrées. Ceci est fait via l'appel à
ReadNonEmptyLine(nAttempts). Si le nom du fichier est lu avec succès (non vide et pas d'erreur de lecture), il continue, sinon il quitte le programme en enregistrant l'erreur fatale.Ensuite, elle tente de créer le fichier spécifié à l'aide de
os.Create(filename). Si une erreur se produit pendant la création du fichier, une erreur fatale est enregistrée et le programme quitte. La fermeture du fichier est reporté après que toutes les opérations suivantes ont été terminées.Elle entre ensuite dans une boucle qui continue jusqu'à ce que
donedevienne vraie.Dans la boucle, elle demande d'abord à l'utilisateur d'entrer son nom, en utilisant une vérification des erreurs similaire à l'entrée précédente. Si le nom est lu avec succès, elle demande ensuite l'âge à l'aide de la fonction
ReadInt(nAttempts). Sinon, elle enregistre l'erreur et répète la boucle.S'il n'y a pas d'erreur lors de la lecture de l'âge, elle formate le nom et l'âge en une chaîne avec
fmt.Sprintf, puis tente d'écrire cette chaîne dans le fichier ouvert à l'aide defile.WriteString(line). Elle vérifie les erreurs lors de l'opération d'écriture, enregistre l'erreur fatale et quitte si nécessaire.Ensuite, elle demande à l'utilisateur s'il souhaite continuer à entrer plus de données. Si l'utilisateur saisit
'N'ou'n', elle changedoneàtruece qui brisera la boucle, sinon elle retourne à la demande du nom et de l'âge.
Note: le paquet encoding/csv offre une meilleure interface pour lire et écrire des fichiers CSV. L'exemple précédent écrit du texte directement dans le fichier. encoding/csv permet de lire et d'écrire plus efficacement. Deux fonctions qui utilisent encoding/csv suivent. La première lit un fichier CSV, et l'autre écrit dans un fichier CSV.