io.WriteSeeker and io.ReadSeeker from []byte or file

Viewed 12685

I have a method called "DoSomething". DoSomething will take binary source data perform an operation on it, and write out binary data. DoSomething needs to be generic enough to handle either a []byte array or a file handle for both the source and destination. To accomplish this, I have attempted to declare the method like this:

func DoSomething(source *io.ReadSeeker, destination *io.WriteSeeker)

I have implemented the ReadSeeker and WriteSeeker for working with buffers, using my own custom, required methods (if there is a way to automatically accomplish this, I'd love to hear about it as well). Unfortunately, I can't seem to figure out how to create either an io.ReadSeeker or io.WriteSeeker from a file handle. I'm fairly sure there must be some pre-cooked way of handling this without having to manually implement them. Is this possible?

3 Answers

For anyone who needs it, here's an implementation of io.ReadWriteSeeker, that supports all I/O operations:

import (
    "errors"
    "fmt"
    "io"
)

// Implements io.ReadWriteSeeker for testing purposes.
type FileBuffer struct {
    buffer []byte
    offset int64
}

// Creates new buffer that implements io.ReadWriteSeeker for testing purposes.
func NewFileBuffer(initial []byte) FileBuffer {
    if initial == nil {
        initial = make([]byte, 0, 100)
    }
    return FileBuffer{
        buffer: initial,
        offset: 0,
    }
}

func (fb *FileBuffer) Bytes() []byte {
    return fb.buffer
}

func (fb *FileBuffer) Len() int {
    return len(fb.buffer)
}

func (fb *FileBuffer) Read(b []byte) (int, error) {
    available := len(fb.buffer) - int(fb.offset)
    if available == 0 {
        return 0, io.EOF
    }
    size := len(b)
    if size > available {
        size = available
    }
    copy(b, fb.buffer[fb.offset:fb.offset+int64(size)])
    fb.offset += int64(size)
    return size, nil
}

func (fb *FileBuffer) Write(b []byte) (int, error) {
    copied := copy(fb.buffer[fb.offset:], b)
    if copied < len(b) {
        fb.buffer = append(fb.buffer, b[copied:]...)
    }
    fb.offset += int64(len(b))
    return len(b), nil
}

func (fb *FileBuffer) Seek(offset int64, whence int) (int64, error) {
    var newOffset int64
    switch whence {
    case io.SeekStart:
        newOffset = offset
    case io.SeekCurrent:
        newOffset = fb.offset + offset
    case io.SeekEnd:
        newOffset = int64(len(fb.buffer)) + offset
    default:
        return 0, errors.New("Unknown Seek Method")
    }
    if newOffset > int64(len(fb.buffer)) || newOffset < 0 {
        return 0, fmt.Errorf("Invalid Offset %d", offset)
    }
    fb.offset = newOffset
    return newOffset, nil
}
Related