Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an io.ReaderAt from io.Reader

Tags:

interface

go

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?

like image 442
Rob Avatar asked Oct 23 '16 15:10

Rob


People also ask

What is io ReadCloser?

You may use it when you have Read and Close methods, an example to show that you may use one common function to work with different types using io.ReadCloser : package main import ( "fmt" "io" "log" "os" ) func main() { f, err := os.Open("./main.go") if err != nil { log.Fatal(err) } doIt(f) doIt(os.Stdin) } func doIt( ...

What is io Reader in GoLang?

The io.Reader interface is used by many packages in the Go standard library and it represents the ability to read a stream of data. More specifically allows you to read data from something that implements the io.Reader interface into a slice of bytes.

What is io EOF in GoLang?

It returns the number of bytes copied and an error if fewer bytes were read. The error is EOF only if no bytes were read. If an EOF happens after reading some but not all the bytes, ReadFull returns ErrUnexpectedEOF.


2 Answers

Something like the below. Note bytes.Reader implements the ReadAt(...) method/function: https://golang.org/pkg/bytes/#Reader.ReadAt. So the line bytes.NewReader is esssentially what you are looking for.

Getting a bytes.Reader:

var ioReader io.Reader
...
buff := bytes.NewBuffer([]byte{})
size, err := io.Copy(buff, ioReader)
if err != nil {
    return err
}

reader := bytes.NewReader(buff.Bytes())
// Do something with `reader`
like image 186
Mohamed Bana Avatar answered Oct 26 '22 17:10

Mohamed Bana


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"
like image 43
Tim Cooper Avatar answered Oct 26 '22 18:10

Tim Cooper