Como leitura / gravação de / para o arquivo usando Go?
Pergunta
Eu tenho tentado aprender Go em meu próprio, mas eu estive perplexo sobre tentando ler e gravar arquivos comuns.
Eu posso chegar tão longe como inFile, _ := os.Open(INFILE, 0, 0)
, mas realmente recebendo o conteúdo do arquivo não faz sentido, porque a função de leitura leva um []byte
como parâmetro.
func (file *File) Read(b []byte) (n int, err Error)
Solução
Vamos fazer ir da lista 1 compatível de todas as formas de ler e arquivos de gravação em Go.
Como arquivo API mudou recentemente ea maioria das outras respostas não funcionam com Go 1. Eles também falta bufio
que é IMHO importante.
Nos exemplos a seguir para copiar um arquivo através da leitura dele e gravar o arquivo de destino.
Iniciar com o básico
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)
}
}
}
Aqui eu usei os.Open
e os.Create
que são wrappers convenientes ao redor os.OpenFile
. Nós normalmente não precisa chamar OpenFile
diretamente.
Observe o tratamento EOF. tentativas Read
para preencher buf
em cada chamada, e retorna io.EOF
como erro se ele atinge o final do arquivo em fazê-lo. Neste caso buf
ainda vai armazenar dados. chamadas consequentes para Read
retorna zero como o número de bytes ler e mesmo io.EOF
como erro. Qualquer outro erro levará a um pânico.
Usando 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
está apenas agindo como um amortecedor aqui, porque não temos muito o que fazer com os dados. Na maioria das outras situações (especialmente com arquivos de texto) bufio
é muito útil, dando-nos uma boa API para ler e escrever com facilidade e flexibilidade, enquanto ele lida com tamponamento nos bastidores.
Usando 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)
}
}
Fácil como a torta! Mas usá-lo apenas se tiver certeza de que você não está lidando com arquivos grandes.
Outras dicas
Esta é uma boa versão:
package main
import (
"io/ioutil";
)
func main() {
contents,_ := ioutil.ReadFile("plikTekstowy.txt")
println(string(contents))
ioutil.WriteFile("filename", contents, 0644)
}
Usando 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)
}
Se você não sente como reinventar a roda, o io.Copy
e io.CopyN
pode atendê-lo bem. Se você verificar a fonte da função io.Copy, é nada, mas uma das soluções do Mostafa (o 'básico', na verdade) embalados na biblioteca Go. Eles estão usando um buffer significativamente maior do que ele é, apesar de tudo.
[]byte
é uma fatia (semelhante a uma subsequência) da totalidade ou de parte de uma matriz de bytes. Pense na fatia como uma estrutura de valor com um campo ponteiro escondida para o sistema para localizar e acessar todas ou parte de uma matriz (a fatia), mais campos para o comprimento e capacidade da fatia, que você pode acessar usando o len()
e funções cap()
.
Aqui está um kit inicial de trabalhar para você, que lê e imprime um arquivo binário; você vai precisar para mudar o inName
valor literal para se referir a um pequeno arquivo em seu sistema.
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();
}
Com mais recentes versões GO, leitura / escrita para / de arquivo é fácil. Para ler a partir de um arquivo:
package main
import (
"fmt"
"io/ioutil"
)
func main() {
data, err := ioutil.ReadFile("text.txt")
if err != nil {
return
}
fmt.Println(string(data))
}
Para escrever para um arquivo:
package main
import "os"
func main() {
file, err := os.Create("text.txt")
if err != nil {
return
}
defer file.Close()
file.WriteString("test\nhello")
}
Este irá substituir o conteúdo de um arquivo (criar um novo arquivo se ele não estava lá).
Tente isto:
package main
import (
"io";
)
func main() {
contents,_ := io.ReadFile("filename");
println(string(contents));
io.WriteFile("filename", contents, 0644);
}
Apenas olhando a documentação parece que você deve apenas declarar um buffer do tipo byte [] e passá-lo para ler o que irá, em seguida, ler até que muitos personagens e retornar o número de caracteres realmente ler (e um erro).
Os docs dizer
Leia lê até len (b) bytes do arquivo. Ele retorna o número de bytes lidos e um erro, se houver. EOF é sinalizado por uma contagem zero com err conjunto de EOF.
Será que isso não funciona?
EDIT:. Além disso, eu acho que talvez você deve usar o leitor / escritor de interfaces declarados no bufio pacote em vez de usar os pacote
O método de leitura leva um parâmetro byte porque esse é o tampão ele irá ler em. É uma expressão comum em alguns círculos e faz algum sentido quando você pensa sobre isso.
Desta forma, você pode determinar quantos bytes serão lidos pelo leitor e inspecionar o retorno para ver quantos bytes realmente foram lidos e lidar com quaisquer erros de forma adequada.
Como outros apontaram em suas respostas bufio é provavelmente o que você quer para a leitura da maioria dos arquivos.
Vou acrescentar uma outra dica, já que é realmente útil. Ler uma linha de um arquivo é melhor não realizado pelo método ReadLine mas os readBytes ou método ReadString vez.