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)
Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top