在go中缓冲实现io.WriterAt

One*_*tay 12 go aws-sdk

我正在使用aws-sdk从s3存储桶下载文件.S3下载功能想要实现io.WriterAt的东西,但bytes.Buffer没有实现它.现在我正在创建一个实现io.WriterAt的文件,但我想要内存中的东西.

Sam*_*Sam 33

对于涉及AWS SDK的情况,请使用aws.WriteAtBuffer将S3对象下载到内存中.

requestInput := s3.GetObjectInput{
    Bucket: aws.String(bucket),
    Key:    aws.String(key),
}

buf := aws.NewWriteAtBuffer([]byte{})
downloader.Download(buf, &requestInput)

fmt.Printf("Downloaded %v bytes", len(buf.Bytes()))
Run Code Online (Sandbox Code Playgroud)

  • 值得注意的是,除非同时耗尽(读取),否则此缓冲区将无限增长(直至文件大小) (2认同)
  • 对 AWS 开发工具包 V2 使用“manager.NewWriteAtBuffer([]byte{})” (2认同)

Coo*_*J86 15

使用 io.Writer 伪造 AWS WriterAt

这不是对原始问题的直接回答,而是我在这里登陆后实际使用的解决方案。这是一个类似的用例,我认为可能会帮助其他人。

AWS 文档定义了合约,如果您设置downloader.Concurrency为 1,您将获得保证的顺序写入。

downloader.Download(FakeWriterAt{w}, s3.GetObjectInput{
    Bucket: aws.String(bucket),
    Key:    aws.String(key),
})
downloader.Concurrency = 1
Run Code Online (Sandbox Code Playgroud)

因此,您可以将 anio.Writer包装起来以实现io.WriterAt,扔掉offset您不再需要的 :

type FakeWriterAt struct {
    w io.Writer
}

func (fw FakeWriterAt) WriteAt(p []byte, offset int64) (n int, err error) {
    // ignore 'offset' because we forced sequential downloads
    return fw.w.Write(p)
}
Run Code Online (Sandbox Code Playgroud)


Mil*_*sen 5

我不知道在标准库中有什么方法可以做到这一点,但您可以编写自己的缓冲区。

真的不会那么难...

编辑:我无法停止思考这个问题,我最终把整个事情都酸化了,享受:)

package main

import (
    "errors"
    "fmt"
)

func main() {
    buff := NewWriteBuffer(0, 10)

    buff.WriteAt([]byte("abc"), 5)
    fmt.Printf("%#v\n", buff)
}

// WriteBuffer is a simple type that implements io.WriterAt on an in-memory buffer.
// The zero value of this type is an empty buffer ready to use.
type WriteBuffer struct {
    d []byte
    m int
}

// NewWriteBuffer creates and returns a new WriteBuffer with the given initial size and
// maximum. If maximum is <= 0 it is unlimited.
func NewWriteBuffer(size, max int) *WriteBuffer {
    if max < size && max >= 0 {
        max = size
    }
    return &WriteBuffer{make([]byte, size), max}
}

// SetMax sets the maximum capacity of the WriteBuffer. If the provided maximum is lower
// than the current capacity but greater than 0 it is set to the current capacity, if
// less than or equal to zero it is unlimited..
func (wb *WriteBuffer) SetMax(max int) {
    if max < len(wb.d) && max >= 0 {
        max = len(wb.d)
    }
    wb.m = max
}

// Bytes returns the WriteBuffer's underlying data. This value will remain valid so long
// as no other methods are called on the WriteBuffer.
func (wb *WriteBuffer) Bytes() []byte {
    return wb.d
}

// Shape returns the current WriteBuffer size and its maximum if one was provided.
func (wb *WriteBuffer) Shape() (int, int) {
    return len(wb.d), wb.m
}

func (wb *WriteBuffer) WriteAt(dat []byte, off int64) (int, error) {
    // Range/sanity checks.
    if int(off) < 0 {
        return 0, errors.New("Offset out of range (too small).")
    }
    if int(off)+len(dat) >= wb.m && wb.m > 0 {
        return 0, errors.New("Offset+data length out of range (too large).")
    }

    // Check fast path extension
    if int(off) == len(wb.d) {
        wb.d = append(wb.d, dat...)
        return len(dat), nil
    }

    // Check slower path extension
    if int(off)+len(dat) >= len(wb.d) {
        nd := make([]byte, int(off)+len(dat))
        copy(nd, wb.d)
        wb.d = nd
    }

    // Once no extension is needed just copy bytes into place.
    copy(wb.d[int(off):], dat)
    return len(dat), nil
}
Run Code Online (Sandbox Code Playgroud)

  • 更喜欢使用 @sam 回答的 `aws.WriteAtBuffer`,而不是滚动自定义解决方案。 (3认同)