two white printer papers near macbook on brown surface

Como ler e escrever arquivo CSV

Quando não temos uma API para realizar integrações, acredito que a utilização de um arquivo CSV para exportar ou importar dados, seja uma das formas mais utilizadas no planeta.

Por isso, se você ainda não se deparou com essa situação, com certeza em algum momento você irá.

Sem mais delongas, bora implementar um pequeno programa para ler um arquivo rh.csv que contém os seguintes dados.

Tiago Temporin,000.000.000-00,32
Maria Costa,111.111.111-11,27
João Augusto,333.333.333-33,22
Marta Leonel,444.444.444-44,40

Para ficar um pouco mais divertido, após ler o arquivo, vamos atribuir os valores a struct definida a baixo.

type Person struct {
	Nome string
	CPF string
	Idade int
}

Lendo arquivo CSV

Com a struct definida, a primeira coisa que vamos fazer é “abrir” o arquivo .csv com a função os.Open.

func main() {
  file, err := os.Open("rh.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

...

Feito isso, o próximo passo é criar um reader e ler o conteúdo do arquivo.

func main() {
	file, err := os.Open("rh.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	records, err := csv.NewReader(file).ReadAll()
	if err != nil {
		panic(err)
	}

...

Se nenhum erro ocorrer, a variável records será um [][]string, ou seja um slice de slice de string, com todos os dados do arquivo CSV.

NOTA: Caso você precise trabalhar com arquivos muito muito muito… grandes, não recomendo utilizar o método ReadAll, pois o mesmo irá ler o arquivo inteiro de uma só vez. Para esses casos, utilize o método Read, que lê uma linha por vez.

Continuando… Agora só precisamos iterar a variável records e atribuir os valores à nossa struct. Abaixo, você pode conferir a versão final do código.

package main

import (
	"encoding/csv"
	"fmt"
	"os"
	"strconv"
)

type Person struct {
	Nome string
	CPF string
	Idade int
}

func main() {
	file, err := os.Open("rh.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	records, err := csv.NewReader(file).ReadAll()
	if err != nil {
		panic(err)
	}

	people := make([]Person, len(records))
	for k, record := range records {
		idade, _ := strconv.Atoi(record[2])
		person := Person{
			Nome: record[0],
			CPF: record[1],
			Idade: idade,
		}

		people[k] = person
	}

	fmt.Println(people)
}

Caso o caracter separador do seu arquivo CSV não seja ,, você precisará fazer a seguinte mudança nas linhas de leitura do CSV.

...
reader := csv.NewReader(file)
reader.Comma = ';'

records, err := reader.ReadAll()
...

Note que o caracter deve ser setado como uma rune e não uma string.

Escrevendo arquivo CSV

Quando vamos escrever um arquivo CSV, a primeira coisa que precisamos fazer é criar um novo arquivo com a função os.Create.

func main() {
	file, err := os.Create("subscribers.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

...

Feito isso, precisamos obter os dados que serão escritos no arquivo. Nesse exemplo eu criei um [][]string com as informações que quero colocar no arquivo.

func main() {
	file, err := os.Create("subscribers.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	records := [][]string{
		{"Tiago Temporin", "tiago.temporin@provedor.com"},
		{"Amanda Moreira", "amanda.moreira@teste.io"},
		{"João Santos", "joao.santos@email.me"},
		{"Valentina Silva", "valentina.silva@tutorial.com"},
	}

...

O próximo passo é iniciar um writer e, para não esquecermos, chamar um defer para o método Flush. Esse passo é necessário pois a escrita dos dados acontece em um buffer, só sendo realmente escritos em um arquivo após a chamada do Flush.

func main() {
	file, err := os.Create("subscribers.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	records := [][]string{
		{"Tiago Temporin", "tiago.temporin@provedor.com"},
		{"Amanda Moreira", "amanda.moreira@teste.io"},
		{"João Santos", "joao.santos@email.me"},
		{"Valentina Silva", "valentina.silva@tutorial.com"},
	}
	
	writer := csv.NewWriter(file)
	defer writer.Flush()

...

Por último, vamos iterar a variável records e escrever os itens no nosso writer.

package main

import (
	"encoding/csv"
	"os"
)

func main() {
	file, err := os.Create("subscribers.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	records := [][]string{
		{"Tiago Temporin", "tiago.temporin@provedor.com"},
		{"Amanda Moreira", "amanda.moreira@teste.io"},
		{"João Santos", "joao.santos@email.me"},
		{"Valentina Silva", "valentina.silva@tutorial.com"},
	}
	
	writer := csv.NewWriter(file)
	defer writer.Flush()

	for _, record := range records {
		if err := writer.Write(record); err != nil {
			panic(err)
		}
	}
}

Caso você já tenha os dados organizados em um [][]string, assim como temos no exemplo, E (ênfase no E), não seja uma quantidade muitooooo grande, onde o muito grande varia de acordo com sua capacidade computacional, você pode obter o mesmo resultado utilizando o método WriteAll.

package main

import (
	"encoding/csv"
	"os"
)

func main() {
	file, err := os.Create("subscribers.csv")
	if err != nil {
		panic(err)
	}
	defer file.Close()

	records := [][]string{
		{"Tiago Temporin", "tiago.temporin@provedor.com"},
		{"Amanda Moreira", "amanda.moreira@teste.io"},
		{"João Santos", "joao.santos@email.me"},
		{"Valentina Silva", "valentina.silva@tutorial.com"},
	}

    err = csv.NewWriter(file).WriteAll(records)
    if err != nil {
        panic(err)
    }
}

Note que não precisamos chamar o método Flush nessa versão, pois sua chamada acontece dentro do próprio método WriteAll.

Nota: Caso seus dados não esteja organizados em um [][]string para o método WriteAll, ou []string para o método Write, é preciso faze-lo antes da chamada deles, pois esses são os tipos de dados que eles aguardam como parâmetro.

Se você quiser continuar lendo sobre manipulação de arquivos em Go, te convido a ler o post “Como manipular arquivos“.

Espero que tenham gostado.

Deixem suas dúvidas nos comentários.

Até a próxima.


Se inscreva na nossa newsletter

* indicates required

Deixe uma resposta