Vamos fazer uma lista compatível com Go 1 de todas as maneiras de ler e gravar arquivos no Go.
Como a API do arquivo foi alterada recentemente e a maioria das outras respostas não funciona com o Go 1. Eles também ignoram o bufio
que é importante no IMHO.
Nos exemplos a seguir, copio um arquivo lendo e escrevendo no arquivo de destino.
Comece 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
quais são embalagens convenientes ao redor os.OpenFile
. Normalmente, não precisamos ligar OpenFile
diretamente.
Aviso tratando EOF. Read
tenta preencher buf
cada chamada e retorna io.EOF
como erro se chegar ao final do arquivo ao fazê-lo. Nesse caso buf
, ainda manterá os dados. Chamadas consequentes para Read
retorna zero como o número de bytes lidos e o mesmo io.EOF
que 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 atuando como um buffer aqui, porque não temos muito a ver com dados. Na maioria das outras situações (especialmente com arquivos de texto)bufio
é muito útil, oferecendo uma boa API para leitura e gravação de maneira fácil e flexível, enquanto lida com o buffer 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 torta! Mas use-o apenas se tiver certeza de que não está lidando com arquivos grandes.
panic("error in writing")
) não é necessária.Esta é uma boa versão:
fonte
0x777
é falso. Em qualquer caso, deve ser mais parecido com0644
ou0755
(octal, não hexadecimal).Usando
io.Copy
Se você não sente como reinventar a roda, o
io.Copy
eio.CopyN
podem atendê-lo bem. Se você verificar a fonte da função io.Copy, ela não passa de uma das soluções do Mostafa (a 'básica', na verdade) empacotada na biblioteca Go. Eles estão usando um buffer significativamente maior do que ele, no entanto.fonte
w.Sync()
após oio.Copy(w, r)
io.Copy()
gravará apenas os dados com os quais você o alimenta; portanto, se o arquivo existente tiver mais conteúdo, ele não será removido, o que pode resultar em um arquivo corrompido.w, err := os.Create("output.txt")
, o que você descreve não acontecerá, porque "Criar cria ou trunca o arquivo nomeado. Se o arquivo já existir, ele será truncado". golang.org/pkg/os/#Create .Com as versões mais recentes do Go, é fácil ler / gravar em / de arquivo. Para ler de um arquivo:
Para gravar em um arquivo:
Isso substituirá o conteúdo de um arquivo (crie um novo arquivo se ele não estiver lá).
fonte
[]byte
é uma fatia (semelhante a uma substring) de todo ou parte de uma matriz de bytes. Pense na fatia como uma estrutura de valor com um campo de ponteiro oculto para o sistema localizar e acessar toda ou parte de uma matriz (a fatia), além de campos para o comprimento e capacidade da fatia, que você pode acessar usando as funçõeslen()
ecap()
.Aqui está um kit inicial para você, que lê e imprime um arquivo binário; você precisará alterar o
inName
valor literal para se referir a um pequeno arquivo em seu sistema.fonte
if
blocoTente o seguinte:
fonte
Olhando apenas para a documentação, parece que você deve declarar um buffer do tipo [] byte e passá-lo para ler, que lerá até muitos caracteres e retornará o número de caracteres realmente lidos (e um erro).
Os documentos dizem
Isso não funciona?
EDIT: Além disso, acho que você talvez deva usar as interfaces Reader / Writer declaradas no pacote bufio em vez de usar o pacote os .
fonte
O método Read usa um parâmetro de byte porque esse é o buffer no qual ele lerá. É um idioma comum em alguns círculos e faz algum sentido quando você pensa sobre isso.
Dessa forma, você pode determinar quantos bytes serão lidos pelo leitor e inspecionar o retorno para ver quantos bytes foram realmente lidos e manipular os erros adequadamente.
Como outros já apontaram em suas respostas, bufio é provavelmente o que você deseja ler na maioria dos arquivos.
Vou adicionar outra dica, já que é realmente útil. A leitura de uma linha de um arquivo é melhor realizada não pelo método ReadLine, mas pelo método ReadBytes ou ReadString.
fonte