Reader

An Introduction to Reader

Reader

Reader is any type that implements the Read method.The io.Reader interface represents an entity from which you can read a stream of bytes. A reader, represented by interface io.Reader, reads data from some source into a transfer buffer where it can be streamed and consumed

type Reader interface {
  Read(p []byte) (n int, err error)
}

Things to note:

  • Read reads up to len(p) bytes into p and returns the number of bytes read – it returns an io.EOF error when the stream ends.
  • After a Read() call, n may be less then len(p)
  • Upon error, Read() may still return n bytes in buffer p
  • If some data is available but not len(p) bytes, Read conventionally returns what is available instead of waiting for more.
  • A call to Read() that returns n=0 and err=nil does not mean EOF as the next call to Read() may return more data.
  • When a Read() exhausts available data, a reader may return a non-zero n and err=io.EOF. However, depending on implementation, a reader may choose to return a non-zero n and err = nil at the end of stream. In that case, any subsequent reads must return n=0, err=io.EOF.

Question:

  • What is the use of Reader?

    You can read from a reader directly (this turns out to be the least useful use case):

    p := make([]byte, 256)
    n, err := r.Read(p)
    

    Example:

Method Read is designed to be called within a loop where, with each iteration, it reads a chunk of data from the source and places it into buffer p. This loop will continue until the method returns an io.EOF error.

package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	r := strings.NewReader("abcde")

	buf := make([]byte, 4)
	for {
		n, err := r.Read(buf)
		fmt.Println(n, err, string(buf[:n]))
		if err == io.EOF {
			break
		}
	}
}

Output:

4 <nil> abcd
1 <nil> e
0 EOF 

Example that shows the contents in the transfer buffer:

package main

import (
	"fmt"
	"io"
	"strings"
)

func main() {
	r := strings.NewReader("abcdef")

	buf := make([]byte, 4)

	for {
		n, err := r.Read(buf)
		fmt.Println(n, err, string(buf))
		if err != nil {
			if err == io.EOF {
				fmt.Println(string(buf))
				break
			}
			fmt.Println(err)
			return
		}
	}
}

Output:

4 <nil> abcd
2 <nil> efcd
0 EOF efcd
efcd

Use io.ReadFull to read exactly len(buf) bytes into buf:

package main

import (
	"fmt"
	"io"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("abcde")

	buf := make([]byte, 4)
	if _, err := io.ReadFull(r, buf); err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(buf))

	if _, err := io.ReadFull(r, buf); err != nil {
		fmt.Println(err)
	}
}

Output:

abcd
unexpected EOF

Use ioutil.ReadAll to read everything:

package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"strings"
)

func main() {
	r := strings.NewReader("abcde")

	buf, err := ioutil.ReadAll(r)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(string(buf))
}

Output:

abcde

Some examples of readers:

  • If you open a file for reading, the object returned is an os.File, which is a Reader (it implements the Read method):
    var r io.Reader
    var err error
    r, err = os.Open("file.txt")
    
  • You can also make a Reader from a normal string using strings.NewReader:
    var r io.Reader
    r = strings.NewReader("Read will return these bytes")
    
  • The body data from an http.Request is a Reader:
    var r io.Reader
    r = request.Body
    
  • A bytes.Buffer is a Reader:
    var r io.Reader
    var buf bytes.Buffer
    r = &buf
    

Tiya Jose ©2019. All rights reserved.

Powered by Hydejack v8.5.1