Backend Development 8 min read

Implementing MultiBytes: Converting [][]byte to io.Reader in Go

This article demonstrates how to implement a MultiBytes struct in Go that converts a [][]byte slice into an io.Reader (and io.Writer), detailing the design, method implementations, and example usage with full source code.

Go Programming World
Go Programming World
Go Programming World
Implementing MultiBytes: Converting [][]byte to io.Reader in Go

The author was prompted by a question in an ekit project group about converting a [][]byte slice to an io.Reader . Remembering a previous hand‑rolled version of io.MultiReader , they decided to create a new implementation called MultiBytes and add unit tests.

Design : The core data structure is a struct with three fields – data [][]byte to store the nested slices, index int to track the outer slice currently being read, and pos int to track the position inside the current inner slice.

type MultiBytes struct {
    data  [][]byte // nested slice storing the bytes
    index int       // outer slice index
    pos   int       // position inside data[index]
}

The public API consists of a constructor NewMultiBytes , a Read method that satisfies io.Reader , and a Write method that satisfies io.Writer . The constructor simply stores the provided data and leaves the indices at zero.

// NewMultiBytes constructs a MultiBytes
func NewMultiBytes(data [][]byte) *MultiBytes {
    return &MultiBytes{data: data}
}

The Read implementation iterates over the nested slices, copying bytes into the supplied buffer p . It handles empty buffers, end‑of‑data (returning io.EOF ), and the case where an inner slice is empty.

// Read implements io.Reader, reading from data into p
func (b *MultiBytes) Read(p []byte) (int, error) {
    if len(p) == 0 {
        return 0, nil
    }
    if b.index >= len(b.data) {
        return 0, io.EOF
    }
    n := 0
    for n < len(p) {
        if b.pos >= len(b.data[b.index]) {
            b.index++
            b.pos = 0
            if b.index >= len(b.data) {
                break
            }
        }
        bytes := b.data[b.index]
        cnt := copy(p[n:], bytes[b.pos:])
        b.pos += cnt
        n += cnt
    }
    if n == 0 {
        return 0, io.EOF
    }
    return n, nil
}

The Write method appends a copy of the incoming byte slice to b.data , ensuring that later modifications of the original slice do not affect the stored data.

// Write implements io.Writer, appending data
func (b *MultiBytes) Write(p []byte) (int, error) {
    if len(p) == 0 {
        return 0, nil
    }
    clone := make([]byte, len(p))
    copy(clone, p)
    b.data = append(b.data, clone)
    return len(p), nil
}

Compile‑time assertions verify that *MultiBytes satisfies both io.Reader and io.Writer interfaces:

var _ io.Reader = (*MultiBytes)(nil)
var _ io.Writer = (*MultiBytes)(nil)

An example program creates a MultiBytes from a slice containing "Hello, World!", writes a Chinese string to it, reads the combined data into a buffer, and prints the result:

package main

import (
    "fmt"
    "github.com/jianghushinian/blog-go-example/iox"
)

func main() {
    mb := iox.NewMultiBytes([][]byte{[]byte("Hello, World!\n")})
    _, _ = mb.Write([]byte("你好,世界!"))
    p := make([]byte, 32)
    _, _ = mb.Read(p)
    fmt.Println(string(p))
}

Running the program prints:

$ go run examples/multi_bytes.go
Hello, World!
你好,世界!

In summary, the article provides a concise, functional implementation that turns a two‑dimensional byte slice into an io.Reader (and io.Writer ), complete with constructor, read/write logic, interface checks, and a runnable example.

backendgoTutorialByte Sliceio.Readerio.WriterMultiBytes
Go Programming World
Written by

Go Programming World

Mobile version of tech blog https://jianghushinian.cn/, covering Golang, Docker, Kubernetes and beyond.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.