Ответ 1
Позвольте составить Go-совместимый список всех способов чтения и записи файлов в Go.
Поскольку API файлов недавно изменился, и большинство других ответов не работают с Go 1. Они также пропускают bufio
, что важно IMHO.
В следующих примерах я копирую файл, читая его и записывая в целевой файл.
Начните с основ
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)
}
}
}
Здесь я использовал os.Open
и os.Create
, которые являются удобными обертками вокруг os.OpenFile
. Обычно нам не нужно напрямую звонить OpenFile
.
Обратите внимание на обработку EOF. Read
пытается заполнить buf
для каждого вызова и возвращает io.EOF
как ошибку, если он достигает конца файла при этом. В этом случае buf
будет хранить данные. Последующие вызовы Read
возвращают ноль в качестве количества прочитанных байтов и того же io.EOF
, что и ошибка. Любая другая ошибка приведет к панике.
Использование 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
просто действует как буфер здесь, потому что мы не имеем ничего общего с данными. В большинстве других ситуаций (особенно с текстовыми файлами) bufio
очень полезно, предоставляя нам хороший API для чтения и записи легко и гибко, в то время как он обрабатывает буферизацию за кулисами.
Использование 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)
}
}
Легко, как пирог! Но используйте его, только если вы уверены, что не имеете дело с большими файлами.