web-dev-qa-db-fra.com

Comment lire / écrire depuis / dans un fichier en utilisant Go?

J'ai essayé d'apprendre par moi-même, mais je suis resté perplexe à essayer de lire et d'écrire dans des fichiers ordinaires.

Je peux aller aussi loin que inFile, _ := os.Open(INFILE, 0, 0), mais obtenir le contenu du fichier n'a pas de sens, car la fonction de lecture prend un paramètre []byte.

func (file *File) Read(b []byte) (n int, err Error)
269
Seth Hoenig

Faisons une liste compatible avec Go 1 de toutes les façons de lire et d’écrire des fichiers dans Go.

Parce que l'API de fichier a changé récemment et que la plupart des autres réponses ne fonctionnent pas avec Go 1. Ils manquent également bufio, ce qui est important à mon humble avis.

Dans les exemples suivants, je copie un fichier en lisant et en écrivant dans le fichier de destination.

Commencez par les bases

package main

import (
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := fi.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := fo.Write(buf[:n]); err != nil {
            panic(err)
        }
    }
}

Ici, j'ai utilisé os.Open et os.Create qui sont des wrappers pratiques autour de os.OpenFile. Nous n'avons généralement pas besoin d'appeler directement OpenFile.

Avis traitant EOF. Read essaie de remplir buf à chaque appel et renvoie io.EOF comme erreur s'il atteint la fin du fichier. Dans ce cas, buf conservera toujours des données. Les appels consécutifs à Read renvoient zéro comme nombre d'octets lus et le même io.EOF comme erreur. Toute autre erreur conduira à une panique.

Utilisation de bufio

package main

import (
    "bufio"
    "io"
    "os"
)

func main() {
    // open input file
    fi, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    // close fi on exit and check for its returned error
    defer func() {
        if err := fi.Close(); err != nil {
            panic(err)
        }
    }()
    // make a read buffer
    r := bufio.NewReader(fi)

    // open output file
    fo, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    // close fo on exit and check for its returned error
    defer func() {
        if err := fo.Close(); err != nil {
            panic(err)
        }
    }()
    // make a write buffer
    w := bufio.NewWriter(fo)

    // make a buffer to keep chunks that are read
    buf := make([]byte, 1024)
    for {
        // read a chunk
        n, err := r.Read(buf)
        if err != nil && err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }

        // write a chunk
        if _, err := w.Write(buf[:n]); err != nil {
            panic(err)
        }
    }

    if err = w.Flush(); err != nil {
        panic(err)
    }
}

bufio agit simplement comme un tampon ici, car nous n’avons pas beaucoup à faire avec les données. Dans la plupart des autres situations (spécialement avec des fichiers texte), bufio est très utile car il nous donne ne API Nice pour lire et écrire facilement et avec souplesse, tout en gérant la mise en mémoire tampon en arrière-plan.

Utilisation de ioutil

package main

import (
    "io/ioutil"
)

func main() {
    // read the whole file at once
    b, err := ioutil.ReadFile("input.txt")
    if err != nil {
        panic(err)
    }

    // write the whole body at once
    err = ioutil.WriteFile("output.txt", b, 0644)
    if err != nil {
        panic(err)
    }
}

C'est de la tarte! Mais utilisez-le uniquement si vous êtes certain de ne pas avoir à gérer de gros fichiers.

452
Mostafa

C'est une bonne version:

package main

import (
  "io/ioutil"; 
  )


func main() {
  contents,_ := ioutil.ReadFile("plikTekstowy.txt")
  println(string(contents))
  ioutil.WriteFile("filename", contents, 0644)
}
47
Piotr

Utilisation de io.Copy

package main

import (
    "io"
    "log"
    "os"
)

func main () {
    // open files r and w
    r, err := os.Open("input.txt")
    if err != nil {
        panic(err)
    }
    defer r.Close()

    w, err := os.Create("output.txt")
    if err != nil {
        panic(err)
    }
    defer w.Close()

    // do the actual work
    n, err := io.Copy(w, r)
    if err != nil {
        panic(err)
    }
    log.Printf("Copied %v bytes\n", n)
}

Si vous ne souhaitez pas réinventer la roue, les io.Copy et io.CopyN peuvent vous être utiles. Si vous vérifiez le source de la fonction io.Copy, ce n'est rien de moins qu'une des solutions de Mostafa (la solution de base, en fait), empaquetée dans la bibliothèque Go. Ils utilisent cependant un tampon beaucoup plus grand que lui.

27
user7610

[]byte est une tranche (semblable à une sous-chaîne) de tout ou partie d'un tableau d'octets. Pensez à la tranche en tant que structure de valeur avec un champ de pointeur masqué permettant au système de localiser et d'accéder à tout ou partie d'un tableau (la tranche), ainsi que des champs pour la longueur et la capacité de la tranche, auxquels vous pouvez accéder à l'aide de la commande len() et cap() fonctions.

Voici un kit de démarrage qui fonctionne pour vous, qui lit et imprime un fichier binaire; vous devrez modifier la valeur littérale inName pour faire référence à un petit fichier sur votre système.

package main
import (
    "fmt";
    "os";
)
func main()
{
    inName := "file-rw.bin";
    inPerm :=  0666;
    inFile, inErr := os.Open(inName, os.O_RDONLY, inPerm);
    if inErr == nil {
        inBufLen := 16;
        inBuf := make([]byte, inBufLen);
        n, inErr := inFile.Read(inBuf);
        for inErr == nil {
            fmt.Println(n, inBuf[0:n]);
            n, inErr = inFile.Read(inBuf);
        }
    }
    inErr = inFile.Close();
}
10
peterSO

Avec les nouvelles versions de Go, il est facile de lire/écrire dans/à partir d’un fichier. Pour lire à partir d'un fichier:

package main

import (
    "fmt"
    "io/ioutil"
)

func main() {
    data, err := ioutil.ReadFile("text.txt")
    if err != nil {
        return
    }
    fmt.Println(string(data))
}

Pour écrire dans un fichier:

package main

import "os"

func main() {
    file, err := os.Create("text.txt")
    if err != nil {
        return
    }
    defer file.Close()

    file.WriteString("test\nhello")
}

Cela écrasera le contenu d'un fichier (créez un nouveau fichier s'il n'y était pas).

8
Salvador Dali

Essaye ça:

package main

import (
  "io"; 
  )


func main() {
  contents,_ := io.ReadFile("filename");
  println(string(contents));
  io.WriteFile("filename", contents, 0644);
}
7
marketer

La méthode Read utilise un paramètre d'octet, car c'est la mémoire tampon dans laquelle elle sera lue. C'est un idiome courant dans certains milieux et prend tout son sens lorsque vous y réfléchissez.

De cette façon, vous pouvez déterminer le nombre d'octets lus par le lecteur et inspecter le retour pour voir combien d'octets ont réellement été lus et gérer les erreurs de manière appropriée.

Comme d'autres l'ont souligné dans leurs réponses, bufio est probablement ce que vous voulez lire dans la plupart des fichiers.

J'ajouterai un autre indice car c'est vraiment utile. La meilleure façon de lire une ligne à partir d'un fichier est de ne pas utiliser la méthode ReadLine, mais plutôt la méthode ReadBytes ou ReadString.

1
Jeremy Wall

Il suffit de regarder la documentation pour déclarer un tampon de type [] octet et le transmettre en lecture, qui lira jusqu’à autant de caractères et renverra le nombre de caractères réellement lus (et une erreur).

Les docs dire

Read lit jusqu'à len (b) octets à partir du fichier. Il renvoie le nombre d'octets lus et une erreur, le cas échéant. EOF est signalé par un compte zéro avec err défini sur EOF.

Ça ne marche pas?

EDIT: De plus, je pense que vous devriez peut-être utiliser les interfaces Reader/Writer déclarées dans le paquet bufio au lieu de paquet os .

1
Hannes Ovrén