Transformando bytes em fluxo: io.Reader a partir de []byte em Go

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Por que você pode precisar transformar bytes em fluxo?

\n\n

Imagine a situação: você escreveu um ótimo serviço em Go que recebe dados de uma API externa. A resposta chega como um array de bytes ([]byte). Tudo bem, mas o problema é que a próxima função no seu pipeline exige como entrada não um slice de bytes, mas uma interface io.Reader. O que fazer? Entrar em pânico? Criar uma solução do zero? Não! Basta lembrar do bytes.NewReader.

\n\n

Esta questão é uma das mais populares no Stack Overflow (milhares de visualizações!). E não é à toa. Em Go, o conceito de io.Reader é a base para trabalhar com fluxos de dados: arquivos, conexões de rede, respostas HTTP e, claro, simplesmente bytes na memória. Se você é um desenvolvedor Go iniciante, mais cedo ou mais tarde vai se deparar com essa barreira. Vamos entender como contorná-la de forma elegante e eficiente.

\n\n

Neste artigo, não vamos apenas dar o comando seco "use bytes.NewReader". Vamos analisar por que isso funciona, quais são as alternativas e mostrar exemplos reais do dia a dia. Vamos lá!

\n\n

Teoria: O que é io.Reader e com o que se come?

\n\n

Antes de converter, vamos lembrar o que é io.Reader. É uma interface definida na biblioteca padrão do Go:

\n\n
type Reader interface {\n    Read(p []byte) (n int, err error)\n}
\n\n

Tudo é genialmente simples. Qualquer estrutura que tenha um método Read(p []byte) (int, error) automaticamente satisfaz a interface io.Reader. Isso permite escrever código universal para ler dados de qualquer fonte: arquivo, socket, string, slice de bytes.

\n\n

Por que isso é legal? Porque você pode escrever uma única função que analisa JSON, XML ou simplesmente copia dados, sem se preocupar de onde eles vieram. Você só precisa de um io.Reader. Isso é uma abstração de fluxo.

\n\n

Mas o que fazer se você já tem os dados na memória (por exemplo, []byte)? Você precisa de um objeto que "finja" ser um fluxo, mas que leia do seu slice. É aqui que entra o bytes.NewReader.

\n\n

Método principal: bytes.NewReader

\n\n

Este é o caminho mais simples e correto. A função bytes.NewReader recebe um []byte e retorna um ponteiro para a estrutura bytes.Reader, que implementa io.Reader (assim como io.ReadSeeker, io.WriterTo e outras interfaces úteis).

\n\n

Exemplo 1: Uso básico

\n\n
package main\n\nimport (\n    "bytes"\n    "fmt"\n    "io"\n    "log"\n)\n\nfunc main() {\n    // Nosso slice de bytes original\n    data := []byte("Olá, mundo! Estes são bytes.")\n\n    // Criando um Reader a partir do slice de bytes\n    reader := bytes.NewReader(data)\n\n    // Lendo dados do reader para um buffer\n    buf := make([]byte, 10) // lendo de 10 em 10 bytes\n    for {\n        n, err := reader.Read(buf)\n        if err != nil {\n            if err == io.EOF {\n                break // leitura finalizada\n            }\n            log.Fatal(err)\n        }\n        fmt.Printf("Lidos %d bytes: %s\\n", n, buf[:n])\n    }\n    // Output:\n    // Lidos 10 bytes: Olá, mund\n    // Lidos 10 bytes: o! Estes s\n    // Lidos 6 bytes: o bytes.\n}
\n\n

Observe: bytes.Reader se comporta como um fluxo real. Quando os dados terminam, ele retorna io.EOF. Tudo honesto.

\n\n

Exemplo 2: Uso com io.Copy

\n\n

O cenário mais comum é copiar bytes para algum lugar (arquivo, resposta HTTP). Para isso, io.Copy é ideal:

\n\n
package main\n\nimport (\n    "bytes"\n    "fmt"\n    "io"\n    "os"\n)\n\nfunc main() {\n    data := []byte("Salvando estes dados em um arquivo.")\n    reader := bytes.NewReader(data)\n\n    // Criando um arquivo\n    file, err := os.Create("output.txt")\n    if err != nil {\n        panic(err)\n    }\n    defer file.Close()\n\n    // Copiando do reader para o arquivo\n                

Blogs

Book Recommendations