Buffered IO

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.

Buffered writers and readers

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.

Scanning the buffer

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:

  • First, use bufio.NewScanner(io.Reader) to create a scanner
  • Call the scanner.Split method to configure how the content is tokenized
  • Traverse the generated tokens with the scanner.Scan method
  • Read the tokenized data with the scanner.Text method

The 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.183.138