io2

package module
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 8, 2026 License: MIT Imports: 10 Imported by: 2

README

github.com/mojatter/io2

PkgGoDev Report Card Coverage Status

Go "io" package utilities.

Delegator

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
}
No-op Closer

Note: NopReadCloser is deprecated since v0.9.0; use the standard library's io.NopCloser instead. The other helpers remain useful because io.NopCloser only accepts a plain io.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)
}

WriteSeeker

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?
}

Multi Readers

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
}

Counting Reader / Writer

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())

Hash Reader

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))

Context Reader / Writer

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

Documentation

Overview

Package io2 provides utilities for the "io" and "io/fs" package.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotImplemented "not implemented"
	ErrNotImplemented = errors.New("not implemented")
)

Functions

func NewContextReader added in v0.9.0

func NewContextReader(ctx context.Context, r io.Reader) io.Reader

NewContextReader returns an io.Reader that returns ctx.Err() once ctx is canceled. The context is checked before each Read call, so an in-flight Read on the underlying reader is not interrupted — use this with readers that return control reasonably often (e.g. network or buffered readers).

func NewContextWriter added in v0.9.0

func NewContextWriter(ctx context.Context, w io.Writer) io.Writer

NewContextWriter returns an io.Writer that returns ctx.Err() once ctx is canceled. The context is checked before each Write call.

func NopReadCloser deprecated

func NopReadCloser(r io.Reader) io.ReadCloser

NopReadCloser returns a ReadCloser with a no-op Close method wrapping the provided interface.

Deprecated: use the standard library's io.NopCloser instead.

func NopReadSeekCloser

func NopReadSeekCloser(r io.ReadSeeker) io.ReadSeekCloser

NopReadSeekCloser returns a ReadSeekCloser with a no-op Close method wrapping the provided interface.

func NopReadWriteCloser

func NopReadWriteCloser(rw io.ReadWriter) io.ReadWriteCloser

NopReadWriteCloser returns a ReadWriteCloser with a no-op Close method wrapping the provided interface.

func NopWriteCloser

func NopWriteCloser(w io.Writer) io.WriteCloser

NopWriteCloser returns a WriteCloser with a no-op Close method wrapping the provided interface.

Types

type CountingReader added in v0.9.0

type CountingReader struct {
	// contains filtered or unexported fields
}

CountingReader wraps an io.Reader and counts the total number of bytes successfully read. It is safe for concurrent use.

Example
package main

import (
	"fmt"
	"io"
	"strings"

	"github.com/mojatter/io2"
)

func main() {
	cr := io2.NewCountingReader(strings.NewReader("hello world"))
	io.Copy(io.Discard, cr)
	fmt.Printf("read %d bytes\n", cr.N())

}
Output:
read 11 bytes

func NewCountingReader added in v0.9.0

func NewCountingReader(r io.Reader) *CountingReader

NewCountingReader returns a CountingReader wrapping r.

func (*CountingReader) N added in v0.9.0

func (c *CountingReader) N() int64

N returns the total number of bytes read so far.

func (*CountingReader) Read added in v0.9.0

func (c *CountingReader) Read(p []byte) (int, error)

Read implements io.Reader.

type CountingWriter added in v0.9.0

type CountingWriter struct {
	// contains filtered or unexported fields
}

CountingWriter wraps an io.Writer and counts the total number of bytes successfully written. It is safe for concurrent use.

func NewCountingWriter added in v0.9.0

func NewCountingWriter(w io.Writer) *CountingWriter

NewCountingWriter returns a CountingWriter wrapping w.

func (*CountingWriter) N added in v0.9.0

func (c *CountingWriter) N() int64

N returns the total number of bytes written so far.

func (*CountingWriter) Write added in v0.9.0

func (c *CountingWriter) Write(p []byte) (int, error)

Write implements io.Writer.

type Delegator

type Delegator struct {
	ReadFunc  func(p []byte) (n int, err error)
	WriteFunc func(p []byte) (n int, err error)
	SeekFunc  func(offset int64, whence int) (int64, error)
	CloseFunc func() error
}

Delegator implements Reader, Writer, Seeker, Closer.

func Delegate

func Delegate(i interface{}) *Delegator

Delegate returns a Delegator with the provided io interfaces (io.Reader, io.Seeker, io.Writer, io.Closer).

func DelegateReadCloser

func DelegateReadCloser(i io.ReadCloser) *Delegator

DelegateReadCloser returns a Delegator with the provided Read and Close functions.

func DelegateReadSeekCloser

func DelegateReadSeekCloser(i io.ReadSeekCloser) *Delegator

DelegateReadSeekCloser returns a Delegator with the provided Read, Seek and Close functions.

func DelegateReadSeeker

func DelegateReadSeeker(i io.ReadSeeker) *Delegator

DelegateReadSeeker returns a Delegator with the provided Read and Seek functions.

func DelegateReadWriteCloser

func DelegateReadWriteCloser(i io.ReadWriteCloser) *Delegator

DelegateReadWriteCloser returns a Delegator with the provided Read, Write and Close functions.

func DelegateReadWriteSeeker

func DelegateReadWriteSeeker(i io.ReadWriteSeeker) *Delegator

DelegateReadWriteSeeker returns a Delegator with the provided Read, Write and Seek functions.

func DelegateReadWriter

func DelegateReadWriter(i io.ReadWriter) *Delegator

DelegateReadWriter returns a Delegator with the provided Read and Write functions.

func DelegateReader

func DelegateReader(i io.Reader) *Delegator

DelegateReader returns a Delegator with the provided Read function.

Example
package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"

	"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 = io.ReadAll(r)
	fmt.Printf("Error: %v\n", err)

}
Output:
Error: custom

func DelegateWriteCloser

func DelegateWriteCloser(i io.WriteCloser) *Delegator

DelegateWriteCloser returns a Delegator with the provided Write and Close functions.

func DelegateWriteSeekCloser

func DelegateWriteSeekCloser(i WriteSeekCloser) *Delegator

DelegateWriteSeekCloser returns a Delegator with the provided Write, Seek and Close functions.

func DelegateWriteSeeker

func DelegateWriteSeeker(i io.WriteSeeker) *Delegator

DelegateWriteSeeker returns a Delegator with the provided Write and Seek functions.

func DelegateWriter

func DelegateWriter(i io.Writer) *Delegator

DelegateWriter returns a Delegator with the provided Write function.

func (*Delegator) Close

func (d *Delegator) Close() error

Close calls CloseFunc().

func (*Delegator) Read

func (d *Delegator) Read(p []byte) (int, error)

Read calls ReadFunc(p).

func (*Delegator) Seek

func (d *Delegator) Seek(offset int64, whence int) (int64, error)

Seek calls SeekFunc(offset, whence).

func (*Delegator) Write

func (d *Delegator) Write(p []byte) (int, error)

Write calls WriteFunc(p).

type HashReader added in v0.9.0

type HashReader struct {
	// contains filtered or unexported fields
}

HashReader wraps an io.Reader and updates a hash.Hash with every byte read. After the underlying reader reaches io.EOF, Sum returns the final digest.

HashReader is useful for verifying content while streaming it elsewhere, for example computing an S3 ETag while uploading.

Example
package main

import (
	"crypto/sha256"
	"fmt"
	"io"
	"strings"

	"github.com/mojatter/io2"
)

func main() {
	hr := io2.NewHashReader(strings.NewReader("the quick brown fox"), sha256.New())
	io.Copy(io.Discard, hr)
	fmt.Printf("%x\n", hr.Sum(nil))

}
Output:
9ecb36561341d18eb65484e833efea61edc74b84cf5e6ae1b81c63533e25fc8f

func NewHashReader added in v0.9.0

func NewHashReader(r io.Reader, h hash.Hash) *HashReader

NewHashReader returns a HashReader that reads from r and writes every byte read into h.

func (*HashReader) Hash added in v0.9.0

func (hr *HashReader) Hash() hash.Hash

Hash returns the underlying hash.Hash.

func (*HashReader) Read added in v0.9.0

func (hr *HashReader) Read(p []byte) (int, error)

Read implements io.Reader.

func (*HashReader) Sum added in v0.9.0

func (hr *HashReader) Sum(b []byte) []byte

Sum appends the current hash digest to b and returns the resulting slice. It is equivalent to calling Sum on the underlying hash.Hash.

type MultiReadCloser

type MultiReadCloser interface {
	MultiReader
	io.Closer
}

MultiReadCloser is the interface that groups the MultiReader and Close methods.

func NewMultiReadCloser

func NewMultiReadCloser(rs ...io.ReadCloser) MultiReadCloser

NewMultiReadCloser create a ReaderCloser that's the logical concatenation of the provided input readers.

type MultiReadSeekCloser

type MultiReadSeekCloser interface {
	MultiReadSeeker
	io.Closer
}

MultiReadSeekCloser is the interface that groups the MultiReadSeeker and Close methods.

func NewMultiFileReader

func NewMultiFileReader(filenames ...string) (MultiReadSeekCloser, error)

func NewMultiReadSeekCloser

func NewMultiReadSeekCloser(rs ...io.ReadSeekCloser) (MultiReadSeekCloser, error)

NewMultiReadSeekCloser creates a ReadSeekCloser that's the logical concatenation of the provided input readers.

type MultiReadSeeker

type MultiReadSeeker interface {
	MultiReader
	io.Seeker
	// SeekReader sets the offset of multiple readers.
	SeekReader(current int) (int64, error)
}

MultiReadSeeker is the interface that groups the MultiReader, Seek and SeekReader methods.

Example
package main

import (
	"fmt"
	"io"
	"strings"

	"github.com/mojatter/io2"
)

func main() {
	r, _ := io2.NewMultiReadSeeker(
		strings.NewReader("Hello !"),
		strings.NewReader(" World"),
	)

	r.Seek(5, io.SeekStart)
	p, _ := io.ReadAll(r)
	fmt.Println(string(p))

	r.Seek(-5, io.SeekEnd)
	p, _ = io.ReadAll(r)
	fmt.Println(string(p))

}
Output:
! World
World

func NewMultiReadSeeker

func NewMultiReadSeeker(rs ...io.ReadSeeker) (MultiReadSeeker, error)

NewMultiReadSeeker creates a ReadSeeker that's the logical concatenation of the provided input readers.

func NewMultiStringReader

func NewMultiStringReader(strs ...string) MultiReadSeeker

type MultiReader

type MultiReader interface {
	io.Reader
	// Current returns a current index of multiple readers. The current starts 0.
	Current() int
}

MultiReader represents a multiple reader.

func NewMultiReader

func NewMultiReader(rs ...io.Reader) MultiReader

NewMultiReader creates a Reader that's the logical concatenation of the provided input readers.

type WriteSeekBuffer

type WriteSeekBuffer struct {
	// contains filtered or unexported fields
}

WriteSeekBuffer implements io.WriteSeeker that using in-memory byte buffer.

func NewWriteSeekBuffer

func NewWriteSeekBuffer(capacity int) *WriteSeekBuffer

NewWriteSeekBuffer returns an WriteSeekBuffer with the initial capacity.

Example
package main

import (
	"fmt"
	"io"

	"github.com/mojatter/io2"
)

func main() {
	o := io2.NewWriteSeekBuffer(0)
	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?

func NewWriteSeekBufferBytes

func NewWriteSeekBufferBytes(buf []byte) *WriteSeekBuffer

NewWriteSeekBufferBytes returns an WriteSeekBuffer with the initial buffer.

func (*WriteSeekBuffer) Bytes

func (b *WriteSeekBuffer) Bytes() []byte

Bytes returns a slice of length b.Len() of the buffer.

func (*WriteSeekBuffer) Close

func (b *WriteSeekBuffer) Close() error

Close calls b.Truncate(0).

func (*WriteSeekBuffer) Len

func (b *WriteSeekBuffer) Len() int

Len returns the number of bytes of the buffer; b.Len() == len(b.Bytes()).

func (*WriteSeekBuffer) Offset

func (b *WriteSeekBuffer) Offset() int

Offset returns the offset.

func (*WriteSeekBuffer) Seek

func (b *WriteSeekBuffer) Seek(offset int64, whence int) (int64, error)

Seek sets the offset for the next Write to offset, interpreted according to whence:

SeekStart means relative to the start of the file,
SeekCurrent means relative to the current offset,
SeekEnd means relative to the end.

Seek returns the new offset relative to the start of the file and an error, if any.

func (*WriteSeekBuffer) Truncate

func (b *WriteSeekBuffer) Truncate(n int)

Truncate changes the size of the buffer with offset.

func (*WriteSeekBuffer) Write

func (b *WriteSeekBuffer) Write(p []byte) (int, error)

Write appends the contents of p to the buffer, growing the buffer as needed. The return value n is the length of p; err is always nil.

type WriteSeekCloser

type WriteSeekCloser interface {
	io.Writer
	io.Seeker
	io.Closer
}

WriteSeekCloser is the interface that groups the basic Write, Seek and Close methods.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL