The goal of this tutorial is to provide a comprehensive understanding of the bufio
package in Go, which allows for buffered I/O operations. Buffered I/O operations are more efficient because they reduce the number of system calls made by reading from or writing to a buffer in memory, rather than directly from or to a disk.
From this tutorial, you will learn:
bufio
package in Go for reading and writing operationsPrerequisites: Basic understanding of Go programming and file operations is required.
The bufio
package in Go provides buffered I/O. It wraps an io.Reader
or io.Writer
object, creating another object (Reader or Writer) that also implements the interface but provides buffering and some help for textual I/O.
bufio
To read a file in Go, we can use the bufio.NewReader
function. This function takes an io.Reader
object, creates a new Reader whose buffer has the default size, and returns it.
file, err := os.Open("test.txt") // For read access.
if err != nil {
log.Fatal(err)
}
defer file.Close()
reader := bufio.NewReader(file)
In this example, we open a file and create a new buffered reader using the bufio.NewReader
function.
bufio
For writing, we can use the bufio.NewWriter
function. This function takes an io.Writer
object, creates a new Writer whose buffer has the default size, and returns it.
file, err := os.Create("test.txt")
if err != nil {
log.Fatal(err)
}
defer file.Close()
writer := bufio.NewWriter(file)
_, err = writer.WriteString("buffered\n") // Write a string
if err != nil {
log.Fatal(err)
}
writer.Flush() // Don't forget to flush!
In the writing example, we create a file, write a string to the file using the WriteString
function, and then flush the buffer with the Flush
function.
Example 1: Reading a File with bufio
package main
import (
"fmt"
"log"
"bufio"
"os"
)
func main() {
file, err := os.Open("test.txt") // Open the file for read access.
if err != nil {
log.Fatal(err)
}
defer file.Close()
scanner := bufio.NewScanner(file) // Create a new Scanner for the file.
for scanner.Scan() { // Read line by line
fmt.Println(scanner.Text()) // Print the line.
}
if err := scanner.Err(); err != nil {
log.Fatal(err) // If there was any error while reading, log it.
}
}
In this example, we are using bufio.NewScanner
to read a file line by line and print each line. scanner.Scan()
reads the next line and removes the newline character from the end. scanner.Text()
returns the current line as a string.
Example 2: Writing to a File with bufio
package main
import (
"log"
"bufio"
"os"
)
func main() {
file, err := os.Create("test.txt") // Create the file for write access.
if err != nil {
log.Fatal(err)
}
defer file.Close()
writer := bufio.NewWriter(file) // Create a new Writer for the file.
_, err = writer.WriteString("Hello, Gophers!") // Write a string
if err != nil {
log.Fatal(err)
}
writer.Flush() // Don't forget to flush!
}
In this example, we write a string to a file using bufio.NewWriter
. writer.WriteString
writes a string to the writer, and writer.Flush
writes any buffered data to the underlying io.Writer
.
In this tutorial, we covered the use of the bufio
package in Go for buffered I/O operations. We learned how to read from and write to files using bufio
, and looked at examples of both. The next step is to practice these concepts through exercises, and then try to apply them in real-world scenarios.
Exercise 1: Read a file and count the number of lines.
Exercise 2: Write a program that takes user input, stores it in a buffer, and then writes it to a file when the user enters 'exit'.
Exercise 3: Modify the program from Exercise 2 so that it writes to the file after every line of input, but still uses buffered I/O.
The solutions to these exercises can be found here. They provide a good starting point for understanding how to use the bufio
package in various scenarios. Remember, the goal is not just to solve the exercises, but to understand how and why the solution works.