liveBook · Manning

Buffering

As explained in Go in Practice, Second Edition

Buffered I/O accumulates input or output in memory buffers so data can be processed or transferred in larger units.

Buffering holds data before it is processed or sent. In Go, a buffered reader can process a file as a stream, while a buffered writer can hold a rendered response until it is safe to send. section 7.1.1 section 9.1.4

Choose the buffer around the failure you need to handle:

  • For newline-delimited records, use bufio.NewScanner with bufio.ScanLines. Decode each line separately so an invalid JSON entry need not stop processing the file. section 7.1.1
  • For a template that might fail during execution, render into a bytes.Buffer. Send its contents to the response writer only if execution succeeds; otherwise, return an error response. section 9.1.4
  • For logs sent to a network service, channels and buffering can improve reliability. Close the connection when finished; closing also flushes its network buffer. section 7.2.1
Listing 7.4 Using bufio to read line by line
package main

import (
    "bufio"
    "encoding/json"
    "log"
    "os"
)

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

    scan := bufio.NewScanner(file)        #1
    scan.Split(bufio.ScanLines)                 #2
    lineJSON := make(map[string]interface{})
    for scan.Scan() {                          #3
        if err := json.Unmarshal([]byte(scan.Text()), &lineJSON); err != n
        il {
            log.Println(err)
        } else {
            log.Println(lineJSON["level"])
        }
    }
}

The scanner reads a structured log one line at a time and attempts to decode each line as JSON. section 7.1.1

Listing 9.7 Buffering a template response
package main

import (
     "bytes"
     "fmt"
     "html/template"
     "io"
     "net/http"
)

var t *template.Template
func init() {
     t = template.Must(template.ParseFiles("./templates/simple.html"))
}
type Page struct {
     Title, Content string
}
func displayPage(w http.ResponseWriter, r *http.Request) {
     p := &Page{
            Title:   "An Example",
            Content: "Have fun stormin' da castle.",
     }
     var b bytes.Buffer         #1
     err := t.Execute(&b, p)    #1
     if err != nil {                           #2
          fmt.Fprint(w, "A error occured.")   
          return
     }
     b.WriteTo(w)    #3
}
func main() {
     http.HandleFunc("/", displayPage)
     http.ListenAndServe(":8080", nil)
}

The handler executes the template into a buffer, checks for an error, then writes the completed output to the client. section 9.1.4

Buffering a template prevents a partially rendered page, but delays the response. Write directly to the response when early delivery matters and execution failures can be handled beforehand. section 9.1.4

How Go in Practice, Second Edition covers it

How deep it goes
Works through line scanning and buffered template execution, including error handling and response-delay trade-offs; only sketches buffering for network logs.
Examples
Shows a scanner processing structured-log lines and a handler rendering a template into bytes.Buffer before responding.
What it assumes
Assumes basic Go file and HTTP handling while demonstrating how to add a scanner or buffer to each workflow.
What you can do after
Apply it via Go's bufio.NewScanner and bytes.Buffer to process line-delimited records and withhold template output until execution succeeds.
How it connects
Connects buffering to streaming I/O, JSON decoding, template execution, HTTP responses, channels, and network logging.

Also explained in

Compare how 5 books explain buffering →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go in Practice, Second Edition. The section links point to the parts of the book it draws on.