Create an io.ReaderAt from io.Reader

go, interface

Solution

Yes, this is possible. As mentioned in my comment above, the implementation is limited in that you cannot seek backward nor can you re-read a section that has already been read.

Here is a example implementation:

type unbufferedReaderAt struct {
    R io.Reader
    N int64
}

func NewUnbufferedReaderAt(r io.Reader) io.ReaderAt {
    return &unbufferedReaderAt{R: r}
}

func (u *unbufferedReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
    if off < u.N {
        return 0, errors.New("invalid offset")
    }
    diff := off - u.N
    written, err := io.CopyN(ioutil.Discard, u.R, diff)
    u.N += written
    if err != nil {
        return 0, err
    }

    n, err = u.R.Read(p)
    u.N += int64(n)
    return
}

Example usage:

s := strings.NewReader("hello world")

var b [5]byte
ura := NewUnbufferedReaderAt(s)
if _, err := ura.ReadAt(b[:], 0); err != nil {
    panic(err)
}
fmt.Printf("%s\n", b[:]) // prints "hello"

/*
if _, err := ura.ReadAt(b[:], 0); err != nil {
    panic(err) // panics
}
fmt.Printf("%s\n", b[:])
*/

if _, err := ura.ReadAt(b[:], 6); err != nil {
    panic(err)
}
fmt.Printf("%s\n", b[:]) // prints "world"

Problem

Is there an implementation of `io.ReaderAt` that can be created from an implementation of `io.Reader` without first being read into a `[]byte` or `string`?

Original source