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)
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.
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)
}
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.
[]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();
}
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).
Essaye ça:
package main
import (
"io";
)
func main() {
contents,_ := io.ReadFile("filename");
println(string(contents));
io.WriteFile("filename", contents, 0644);
}
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.
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 .