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.