Zróbmy listę kompatybilną z Go 1 wszystkich sposobów odczytu i zapisu plików w Go.
Ponieważ interfejs API plików ostatnio się zmienił i większość innych odpowiedzi nie działa z Go 1. Oni również tęsknią bufio
ważnego IMHO.
W poniższych przykładach kopiuję plik, czytając go i zapisując do pliku docelowego.
Zacznij od podstaw
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)
}
}
}
Tutaj użyłem os.Open
i os.Create
które są wygodnymi opakowaniami os.OpenFile
. Zwykle nie musimy dzwonić OpenFile
bezpośrednio.
Zwróć uwagę na leczenie EOF. Read
próbuje wypełnić buf
każde wywołanie i zwraca io.EOF
jako błąd, jeśli do tego dojdzie do końca pliku. W takim przypadku buf
nadal będą przechowywane dane. Kolejne wywołania Read
zwracają zero jako liczbę odczytanych bajtów i taką samą io.EOF
jak błąd. Każdy inny błąd doprowadzi do paniki.
Za pomocą 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
działa tutaj tylko jako bufor, ponieważ nie mamy wiele wspólnego z danymi. W większości innych sytuacji (szczególnie z plikami tekstowymi) bufio
jest bardzo przydatny, ponieważ zapewnia nam przyjemny interfejs API do łatwego i elastycznego czytania i pisania, a także obsługuje buforowanie za sceną.
Za pomocą 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)
}
}
Proste jak ciasto! Ale używaj go tylko wtedy, gdy masz pewność, że nie masz do czynienia z dużymi plikami.