Skip to Content
Course content

50: Working with Buffers: bytes.Buffer

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Why should I use a buffer instead of just adding strings together?

If you're just joining two or three strings, honestly, just use the + operator or fmt.Sprintf. It's readable and fast enough. But here is where you'll run into trouble: when you're building a large string inside a loop.

In Go, strings are immutable. Every time you do s += "more text", Go isn't just appending to the end of the existing string; it's creating a brand new string in memory and copying the old contents over. If you do this a thousand times in a loop, you're creating a thousand temporary strings that the garbage collector eventually has to clean up. It's a performance killer.

bytes.Buffer solves this by maintaining a slice of bytes that grows dynamically. It allocates more space in chunks, meaning it doesn't have to re-allocate and copy every single time you add a piece of data. I usually reach for a buffer the moment I see a loop that's assembling a long message or a document.

How do I actually put data in and get it out?

Using a buffer is pretty intuitive. You create an instance, write to it, and then call .String() when you're done. I personally use WriteString most of the time because it's cleaner than converting everything to []byte.

package main

import (
	"bytes"
	"fmt"
)

func main() {
	var buf bytes.Buffer

	// We can write strings directly
	buf.WriteString("User Report\n")
	buf.WriteString("------------\n")

	// Or we can write raw bytes
	buf.Write([]byte{65, 66, 67}) // Writes "ABC"

	// You can even use fmt.Fprintf to format data directly into the buffer
	fmt.Fprintf(&buf, "\nID: %d | Status: %s", 101, "Active")

	fmt.Println(buf.String())
}

One thing to keep in mind: buf.String() returns a copy of the data as a string. If you're passing this data straight into another function that accepts a byte slice, use buf.Bytes() instead to avoid that extra allocation.

Can I use this with other Go interfaces like io.Writer?

This is actually the "secret sauce" of bytes.Buffer. Because it implements the io.Writer and io.Reader interfaces, it can act as a bridge between different parts of your program.

Imagine you have a function that encodes data (like JSON or XML) and requires an io.Writer. Instead of writing that data directly to a file or a network socket—where you can't "take it back" if something goes wrong—you can write it to a buffer first. Once you've verified the buffer contains what you expect, you can then send that buffer's contents to the final destination.

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
)

type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	user := User{Name: "Alice", Age: 30}
	var buf bytes.Buffer

	// json.NewEncoder takes an io.Writer. 
	// bytes.Buffer fits that perfectly.
	encoder := json.NewEncoder(&buf)
	if err := encoder.Encode(user); err != nil {
		fmt.Println("Error encoding:", err)
		return
	}

	fmt.Println("Buffered JSON:", buf.String())
}

I find this incredibly useful for unit testing. You can pass a bytes.Buffer into a function that normally writes to a file, then simply inspect the buffer's string output to assert that the function wrote the correct data.




📋 Practical Task

Exercise: Building a Dynamic CSV Row Generator

In this exercise, you will create a function that takes a slice of strings and converts them into a single CSV-formatted row. Instead of using string concatenation, you must use bytes.Buffer to build the resulting string.

  • Create a function GenerateCSVRow(columns []string) string.
  • The function should join each element of the slice with a comma (,).
  • Ensure there is no trailing comma at the end of the string.
  • Use bytes.Buffer and its WriteString method to assemble the row.
  • Test your function with a slice like []string{"John Doe", "Software Engineer", "New York", "USA"} to ensure the output is "John Doe,Software Engineer,New York,USA".
Rating
0 0

There are no comments for now.

to be the first to leave a comment.