Go "io" package utilities.
- Delegator
- No-op Closer
- WriteSeeker
- Multi Readers
- Counting Reader / Writer
- Hash Reader
- Context Reader / Writer
Delegator implements io.Reader, io.Writer, io.Seeker, io.Closer. Delegator can override the I/O functions that is useful for unit tests.
package main
import (
"bytes"
"errors"
"fmt"
"io/ioutil"
"github.com/mojatter/io2"
)
func main() {
org := bytes.NewReader([]byte(`original`))
r := io2.DelegateReader(org)
r.ReadFunc = func(p []byte) (int, error) {
return 0, errors.New("custom")
}
var err error
_, err = ioutil.ReadAll(r)
fmt.Printf("Error: %v\n", err)
// Output: Error: custom
}Note:
NopReadCloseris deprecated since v0.9.0; use the standard library'sio.NopCloserinstead. The other helpers remain useful becauseio.NopCloseronly accepts a plainio.Reader.
// NopReadCloser returns a ReadCloser with a no-op Close method wrapping the provided interface.
// Deprecated: use io.NopCloser.
func NopReadCloser(r io.Reader) io.ReadCloser {
return DelegateReader(r)
}
// NopReadWriteCloser returns a ReadWriteCloser with a no-op Close method wrapping the provided interface.
func NopReadWriteCloser(rw io.ReadWriter) io.ReadWriteCloser {
return DelegateReadWriter(rw)
}
// NopReadSeekCloser returns a ReadSeekCloser with a no-op Close method wrapping the provided interface.
func NopReadSeekCloser(r io.ReadSeeker) io.ReadSeekCloser {
return DelegateReadSeeker(r)
}
// NopWriteCloser returns a WriteCloser with a no-op Close method wrapping the provided interface.
func NopWriteCloser(w io.Writer) io.WriteCloser {
return DelegateWriter(w)
}WriteSeekBuffer implements io.Writer, io.Seeker and io.Closer. NewWriteSeekBuffer(capacity int) returns the buffer.
// WriteSeekCloser is the interface that groups the basic Write, Seek and Close methods.
type WriteSeekCloser interface {
io.Writer
io.Seeker
io.Closer
}package main
import (
"fmt"
"io"
"github.com/mojatter/io2"
)
func main() {
o := io2.NewWriteSeekBuffer(16)
o.Write([]byte(`Hello!`))
o.Truncate(o.Len() - 1)
o.Write([]byte(` world!`))
fmt.Println(string(o.Bytes()))
o.Seek(-1, io.SeekEnd)
o.Write([]byte(`?`))
fmt.Println(string(o.Bytes()))
// Output:
// Hello world!
// Hello world?
}io2 provides MultiReadCloser, MultiReadSeeker, MultiReadSeekCloser.
package main
import (
"fmt"
"io"
"io/ioutil"
"strings"
"github.com/mojatter/io2"
)
func main() {
r, _ := io2.NewMultiReadSeeker(
strings.NewReader("Hello !"),
strings.NewReader(" World"),
)
r.Seek(5, io.SeekStart)
p, _ := ioutil.ReadAll(r)
fmt.Println(string(p))
r.Seek(-5, io.SeekEnd)
p, _ = ioutil.ReadAll(r)
fmt.Println(string(p))
// Output:
// ! World
// World
}CountingReader and CountingWriter track the total number of bytes
transferred through them. They are safe for concurrent use and useful for
progress reporting.
cr := io2.NewCountingReader(resp.Body)
io.Copy(dst, cr)
fmt.Printf("read %d bytes\n", cr.N())HashReader updates a hash.Hash with every byte read, so you can verify or
fingerprint content while streaming it elsewhere — for example computing an S3
ETag while uploading.
hr := io2.NewHashReader(file, sha256.New())
io.Copy(uploader, hr)
fmt.Printf("sha256=%x\n", hr.Sum(nil))NewContextReader and NewContextWriter abort reads and writes once the
supplied context.Context is canceled. The context is checked before each
call, so they work best with readers and writers that return control
frequently (network, buffered I/O).
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
r := io2.NewContextReader(ctx, conn)
_, err := io.Copy(dst, r) // returns context.DeadlineExceeded on timeout