Most IO operations covered so far have been unbuffered. This implies that each read and write operation could be negatively impacted by the latency of the underlying OS to handle IO requests. Buffered operations, on the other hand, reduces latency by buffering data in internal memory during IO operations. The bufio
package (https://golang.org/pkg/bufio/) offers functions for buffered read and write IO operations.
The bufio
package offers several functions to do buffered writing of IO streams using an io.Writer
interface. The following snippet creates a text file and writes to it using buffered IO:
func main() { rows := []string{ "The quick brown fox", "jumps over the lazy dog", } fout, err := os.Create("./filewrite.data") writer := bufio.NewWriter(fout) if err != nil { fmt.Println(err) os.Exit(1) } defer fout.Close() for _, row := range rows { writer.WriteString(row) } writer.Flush() }
golang.fyi/ch10/bufwrite0.go
In general, the constructor functions in the bufio
package create a buffered writer by wrapping an existing io.Writer
as its underlying source. For instance, the previous code creates a buffered writer using the bufio.NewWriter
function by wrapping the io.File variable, fout
.
To influence the size of the internal buffer, use the constructor function bufio.NewWriterSize(w io.Writer, n int)
to specify the internal buffer size. The bufio.Writer
type also offers the methods Write
and WriteByte
for writing raw bytes and WriteRune
for writing Unicode-encoded characters.
Reading buffered streams can be done simply by calling the constructor function bufio.NewReader to wrap an existing io.Reader
. The following code snippet creates a bufio.Reader
variable reader
by wrapping the file
variable as its underlying source:
func main() { file, err := os.Open("./bufread0.go") if err != nil { fmt.Println("Unable to open file:", err) return } defer file.Close() reader := bufio.NewReader(file) for { line, err := reader.ReadString(' ') if err != nil { if err == io.EOF { break } else { fmt.Println("Error reading:, err") return } } fmt.Print(line) } }
golang.fyi/ch10/bufread0.go
The previous code uses the reader.ReadString
method to read a text file using the '
'
character as the content delimiter. To influence the size of the internal buffer, use the constructor function bufio.NewReaderSize(w io.Reader, n int)
to specify the internal buffer size. The bufio.Reader
type also offers the Read, ReadByte, and ReadBytes methods for reading raw bytes from a stream and the ReadRune method for reading Unicode-encoded characters.
The bufio
package also makes available primitives that are used to scan and tokenize buffered input data from an io.Reader
source. The bufio.Scanner
type scans input data using the Split method to define tokenization strategies. The following code snippet shows a reimplementation of the planetary example (from earlier). This time, the code uses bufio.Scanner
(instead of the fmt.Fscan
function) to scan the content of the text file using the bufio.ScanLines
function:
func main() { file, err := os.Open("./planets.txt") if err != nil { fmt.Println("Unable to open file:", err) return } defer file.Close() fmt.Printf( "%-10s %-10s %-6s %-6s ", "Planet", "Diameter", "Moons", "Ring?", ) scanner := bufio.NewScanner(file) scanner.Split(bufio.ScanLines) for scanner.Scan() { fields := strings.Split(scanner.Text(), " ") fmt.Printf( "%-10s %-10s %-6s %-6s ", fields[0], fields[1], fields[2], fields[3], ) } }
golang.fyi/ch10/bufscan0.go
Using bufio.Scanner
is done in four steps as shown in the previous example:
bufio.NewScanner(io.Reader)
to create a scannerscanner.Split
method to configure how the content is tokenizedscanner.Scan
methodscanner.Text
methodThe code uses the pre-defined function bufio.ScanLines
to parse the buffered content using a line-delimiter. The bufio
package comes with several pre-defined splitter functions including ScanBytes to scan each byte as a token, ScanRunes to scan UTF-8 encoded tokens, and ScanWords which scan each space-separated words as tokens.
3.135.183.138