Lire et écrire dans un fichier dans le langage de programmation Go

Ce chapitre va vous apprendre comment vous pouvez efficacement lire et écrire sur des fichiers à l'aide du langage de programmation go.

Introduction

Dans ce chapitre, nous allons voir comment vous pouvez efficacement lire et écrire sur des fichiers à l'aide du langage de programmation go.

Il existe de multiples façons pour lire et écrire dans un fichier. Dans les exemples qui suivent je vais vous montrer les techniques que j'utilise selon les différents cas d'utilisation que je juge le plus simple.

Je vais manipuler un fichier nommé test.txt avec le contenu suivant :

je suis un fichier de test

Lire seulement un fichier

Dans le cas ou vous ne faites que lire un fichier, le mieux reste d'utiliser la fonction ReadFile() de la bibliothèque io/ioutil. Cette fonction retourne un type byte (bit), il faut donc penser à caster (convertir le type) le résultat obtenu en string

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("test.txt") // lire le fichier text.txt
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(string(data)) // conversion de byte en string
}

Résultat :

je suis un fichier de test

Dans le cas ou le fichier n'existe pas, vous aurez l'erreur suivante :

Le fichier spécifié est introuvable.

Écrire sur un fichier

il y a deux manières pour écrire dans un fichier. Soit vous décidez d'écraser un fichier après écriture, soit d'écrire à la suite du contenu du fichier.

Pour écrire dans un fichier on va utiliser la bibliothèque os.

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func main() {
    file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
    defer file.Close() // on ferme automatiquement à la fin de notre programme

    if err != nil {
        panic(err)
    }

    _, err = file.WriteString("test\n") // écrire dans le fichier
    if err != nil {
        panic(err)
    }

    _, err = file.WriteString("i love test\n")
    if err != nil {
        panic(err)
    }

    data, err := ioutil.ReadFile("test.txt") // lire le fichier
    if err != nil {
        fmt.Println(err)
    }

    fmt.Print(string(data))
}

Information

J'utilise le "\n" pour faire un saut de la ligne dans mon fichier.

Résultat :

je suis un fichier de test
test
i love test

Je reviens ici sur ces lignes de code :

file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
defer file.Close() // on ferme automatiquement le fichier après l'avoir manipulé

La fonction os.OpenFile(), propose vraiment beaucoup d'options, que je vous explique ci-dessous :

  • Premier paramètre : correspond au nom du fichier à ouvrir
  • Deuxième paramètre : ici ce sont des options spécialement dédiées au fichier que vous allez manipuler :
    • os.O_CREATE : Permet de créer le fichier si il n'existe pas.
    • os.O_WRONLY : Permet de rendre le fichier (dans votre programme) accessible en écriture seulement.
    • os.O_APPEND : Permet de ne pas écraser le fichier quand vous écrivez dessus (supprimez cette option si vous souhaitez écraser le fichier).
  • Troisième paramètre : les droits d'accès de votre fichier (Plus d'information sur les permissions ici ici)

Il est absolument important de fermer le fichier à la fin de votre programme. D'où l'utilisation de la fonction close(), j'ai rajouté le mot clé defer, ce mot-clé permet d'exécuter la ligne de code en question jusqu'à la fin d'exécution d'une fonction.

Bonus

On se retrouve avec beaucoup de lignes de code répétables, il serait temps d'utiliser les super pouvoirs des fonctions pour mieux structurer notre code :

package main

import (
    "fmt"
    "io/ioutil"
    "os"
)

func check(e error) {
    if e != nil {
        panic(e)
    }
}

func write(text string, file *os.File) {
    if _, err := file.WriteString(text); err != nil {
        panic(err)
    }
}

func read(filename string) string {
    data, err := ioutil.ReadFile(filename)
    check(err)
    return string(data)
}

func main() {
    file, err := os.OpenFile("test.txt", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0600)
    defer file.Close()
    check(err)

    write("Test\n", file)

    data := read(file.Name())
    fmt.Print(data)
}

Résultat :

je suis un fichier de test
test
i love test
Test

Exercice.

Voilà maintenant vous savez comment lire et écrire dans un fichier. Si vous souhaitez aller encore plus loin, vous pouvez reprendre le tp du morpions pour rajouter un système qui vous permet de sauvegarder la partie en cours (tour du joueur et le damier).

Espace commentaire

Écrire un commentaire

Rejoignez la discussion

Vous devez être connecté pour poster un message.

30 commentaires

ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Oui, appelle file.Sync() après tes écritures. C'est plus lent mais plus sûr en cas de crash brutal.

13/04/2019 à 04:19
isaac75
Membre Actif
Avatar de isaac75
isaac75
Membre Actif

Je peux forcer l'écriture sur disque sans attendre le flush du cache OS ?

12/04/2019 à 22:27
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Ta RAM. Si le fichier fait 10Go, tu vas faire un OOM. Utilise des streams pour les gros fichiers.

12/04/2019 à 18:12
letellier-raymond
Membre Actif
Avatar de letellier-raymond
letellier-raymond
Membre Actif

C'est quoi la limite de taille pour os.ReadFile ?

12/04/2019 à 13:57
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Top. Si tu veux pousser, regarde le format JSON pour sauvegarder l'état complexe de ta grille plutôt que du texte brut.

12/04/2019 à 08:15
noemi44
Membre Actif
Avatar de noemi44
noemi44
Membre Actif

J'ai réussi à implémenter la sauvegarde du morpion, merci pour le tuto !

12/04/2019 à 02:56
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

file.Write([]byte). Évite WriteString qui attend du texte encodé.

11/04/2019 à 20:05

Comment je fais pour écrire des données binaires et pas juste du texte ?

11/04/2019 à 16:04
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Vérifie ton Working Directory au lancement. Utilise os.Getwd() pour voir où le binaire cherche réellement.

11/04/2019 à 10:41
andre52
Membre Actif Rédacteur
Avatar de andre52
andre52
Membre Actif Rédacteur

Mon programme Go ne trouve pas le fichier alors qu'il est bien dans le dossier. Une idée ?

11/04/2019 à 04:30
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Carrément. Ça évite de répéter le if err != nil partout, surtout quand tu as beaucoup d'opérations IO.

10/04/2019 à 22:44
msanchez
Membre Actif
Avatar de msanchez
msanchez
Membre Actif

Le check(e error) dans le bonus, c'est pas mal pour aérer le code.

10/04/2019 à 15:59
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Ça dépend de ton umask système. Le 0600 est filtré par le masque de ton shell.

10/04/2019 à 11:44
laurent55
Membre Actif Rédacteur
Avatar de laurent55
laurent55
Membre Actif Rédacteur

J'ai un souci avec os.O_CREATE, il me crée le fichier mais avec des droits bizarres.

10/04/2019 à 05:46
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

ioutil.ReadFile charge tout. Utilise bufio.Scanner pour lire ton fichier par chunks.

09/04/2019 à 22:58
collin-mathilde
Membre Actif
Avatar de collin-mathilde
collin-mathilde
Membre Actif

Comment je peux lire un gros fichier ligne par ligne sans tout charger en mémoire ?

09/04/2019 à 15:11
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

En prod, oui. C'est pour l'exemple. Remplace par un retour d'erreur classique et gère ton flow proprement.

09/04/2019 à 08:19
kguillou
Membre Actif
Avatar de kguillou
kguillou
Membre Actif

Le panic c'est pas un peu violent pour gérer des erreurs de fichier ?

09/04/2019 à 01:21
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

N'oublie pas le dans ta chaîne de caractères quand tu fais ton file.WriteString.

08/04/2019 à 18:49
pires-nath
Membre Actif
Avatar de pires-nath
pires-nath
Membre Actif

J'essaie de concaténer des logs mais ça me fout tout sur la même ligne.

08/04/2019 à 14:38
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Bien vu, depuis Go 1.16, utilise le package os directement pour os.ReadFile. C'est devenu le standard.

08/04/2019 à 09:27
philippe-jeanne
Membre Actif
Avatar de philippe-jeanne
philippe-jeanne
Membre Actif

J'ai une erreur sur ioutil, il me dit que c'est déprécié sur les versions récentes de Go.

08/04/2019 à 01:46
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Parce que si ton programme plante avec un panic avant la fin, le fichier reste ouvert. Ne jamais oublier le defer pour éviter les fuites de descripteurs.

07/04/2019 à 17:57
xavier-guillot
Membre Actif
Avatar de xavier-guillot
xavier-guillot
Membre Actif

C'est quoi l'intérêt du defer file.Close() ? Pourquoi pas juste le fermer à la fin ?

07/04/2019 à 10:57
ajdaini-hatim
Auteur Rédacteur Secouriste Actif
Avatar de ajdaini-hatim
ajdaini-hatim
Auteur Rédacteur Secouriste Actif

Exact. Et ajoute os.O_TRUNC si tu veux être sûr de repartir de zéro à chaque ouverture.

07/04/2019 à 06:00

Rejoindre la communauté

Recevoir les derniers articles gratuitement en créant un compte !

S'inscrire