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

huangapple go评论75阅读模式
英文:

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

问题

我有一个名为"DoSomething"的方法。DoSomething将对二进制源数据执行操作,并将结果写入二进制数据。DoSomething需要足够通用,能够处理[]byte数组或文件句柄作为源和目标。为了实现这一点,我尝试像这样声明该方法:

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

我已经实现了用于处理缓冲区的ReadSeeker和WriteSeeker,使用了我自己的自定义必需方法(如果有一种自动完成这个过程的方法,我也很想知道)。不幸的是,我似乎无法从文件句柄创建io.ReadSeeker或io.WriteSeeker。我相当确定必须有一些现成的方法来处理这个问题,而不必手动实现它们。这种可能吗?

英文:

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?

答案1

得分: 14

一个文件已经实现了这两个功能。你可以像这样做:

package main

import (
   "fmt"
   "io"
   "os"
)

func main() {
   f, err := os.Open("test.txt")
   if err != nil {
     fmt.Println(err)
   }
   defer f.Close()
   f2, err := os.Create("test2.txt")
   if err != nil {
      fmt.Println(err)
   }
   defer f2.Close()
   DoSomething(f, f2) 
}

func DoSomething(source io.ReadSeeker, destination io.WriteSeeker) {
   io.Copy(destination, source)
}

另外,你不需要传递接口的指针,这样处理起来更容易。

英文:

A file already implements both of those. You can do something like this:

package main

import (
   "fmt"
   "io"
   "os"
)

func main() {
   f, err := os.Open("test.txt")
   if err != nil {
     fmt.Println(err)
   }
   defer f.Close()
   f2, err := os.Create("test2.txt")
   if err != nil {
      fmt.Println(err)
   }
   defer f2.Close()
   DoSomething(f, f2) 
}

func DoSomething(source io.ReadSeeker, destination io.WriteSeeker) {
   io.Copy(destination, source)
}

Also, you don't need to pass pointers to interfaces, which makes it easier to deal with them.

答案2

得分: 9

对于其他需要完成类似任务的人,这是我最终得到的代码。它并不完整,但对于我所需的功能已经足够接近了:

package filebuffer

import (
	"bytes"
	"errors"
)

type FileBuffer struct {
	Buffer bytes.Buffer
	Index  int64
}

func NewFileBuffer() FileBuffer {
	return FileBuffer{}
}

func (fbuffer *FileBuffer) Bytes() []byte {
	return fbuffer.Buffer.Bytes()
}

func (fbuffer *FileBuffer) Read(p []byte) (int, error) {
	n, err := bytes.NewBuffer(fbuffer.Buffer.Bytes()[fbuffer.Index:]).Read(p)

	if err == nil {
		if fbuffer.Index+int64(len(p)) < int64(fbuffer.Buffer.Len()) {
			fbuffer.Index += int64(len(p))
		} else {
			fbuffer.Index = int64(fbuffer.Buffer.Len())
		}
	}

	return n, err
}

func (fbuffer *FileBuffer) Write(p []byte) (int, error) {
	n, err := fbuffer.Buffer.Write(p)

	if err == nil {
		fbuffer.Index = int64(fbuffer.Buffer.Len())
	}

	return n, err
}

func (fbuffer *FileBuffer) Seek(offset int64, whence int) (int64, error) {
	var err error
	var Index int64 = 0

	switch whence {
	case 0:
		if offset >= int64(fbuffer.Buffer.Len()) || offset < 0 {
			err = errors.New("Invalid Offset.")
		} else {
			fbuffer.Index = offset
			Index = offset
		}
	default:
		err = errors.New("Unsupported Seek Method.")
	}

	return Index, err
}

然后你可以像这样使用它:

destination := filebuffer.NewFileBuffer()

source, err := os.Open(pathString)
if err != nil {
    return nil, err
}
defer source.Close()

if _, err := encrypter.Decrypt(source, &destination, password); err != nil {
    return nil, err
}

希望对你有帮助!

英文:

For anyone else who needs to accomplish something like this, here's what I ended up with. It isn't complete, but it is close enough for what I needed:

package filebuffer
import (
&quot;bytes&quot;
&quot;errors&quot;
)
type FileBuffer struct {
Buffer bytes.Buffer
Index  int64
}
func NewFileBuffer() FileBuffer {
return FileBuffer{}
}
func (fbuffer *FileBuffer) Bytes() []byte {
return fbuffer.Buffer.Bytes()
}
func (fbuffer *FileBuffer) Read(p []byte) (int, error) {
n, err := bytes.NewBuffer(fbuffer.Buffer.Bytes()[fbuffer.Index:]).Read(p)
if err == nil {
if fbuffer.Index+int64(len(p)) &lt; int64(fbuffer.Buffer.Len()) {
fbuffer.Index += int64(len(p))
} else {
fbuffer.Index = int64(fbuffer.Buffer.Len())
}
}
return n, err
}
func (fbuffer *FileBuffer) Write(p []byte) (int, error) {
n, err := fbuffer.Buffer.Write(p)
if err == nil {
fbuffer.Index = int64(fbuffer.Buffer.Len())
}
return n, err
}
func (fbuffer *FileBuffer) Seek(offset int64, whence int) (int64, error) {
var err error
var Index int64 = 0
switch whence {
case 0:
if offset &gt;= int64(fbuffer.Buffer.Len()) || offset &lt; 0 {
err = errors.New(&quot;Invalid Offset.&quot;)
} else {
fbuffer.Index = offset
Index = offset
}
default:
err = errors.New(&quot;Unsupported Seek Method.&quot;)
}
return Index, err
}

You then use it like this:

destination := filebuffer.NewFileBuffer()
source, err := os.Open(pathString)
if err != nil {
return nil, err
}
defer source.Close()
if _, err := encrypter.Decrypt(source, &amp;destination, password); err != nil {
return nil, err
}

答案3

得分: 0

对于需要的任何人,这是一个支持所有I/O操作的io.ReadWriteSeeker实现:

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

// 用于测试目的实现io.ReadWriteSeeker。
type FileBuffer struct {
	buffer []byte
	offset int64
}

// 创建一个新的缓冲区,用于测试目的实现io.ReadWriteSeeker。
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("未知的Seek方法")
	}
	if newOffset > int64(len(fb.buffer)) || newOffset < 0 {
		return 0, fmt.Errorf("无效的偏移量 %d", offset)
	}
	fb.offset = newOffset
	return newOffset, nil
}

希望对你有帮助!

英文:

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

import (
	&quot;errors&quot;
	&quot;fmt&quot;
	&quot;io&quot;
)

// 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 &gt; 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 &lt; 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(&quot;Unknown Seek Method&quot;)
	}
	if newOffset &gt; int64(len(fb.buffer)) || newOffset &lt; 0 {
		return 0, fmt.Errorf(&quot;Invalid Offset %d&quot;, offset)
	}
	fb.offset = newOffset
	return newOffset, nil
}

huangapple
  • 本文由 发表于 2013年12月16日 09:30:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/20602131.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定