gpt4 book ai didi

go - 在 Go 中使用没有文件的 io.WriteSeeker

转载 作者:IT王子 更新时间:2023-10-29 01:21:07 24 4
gpt4 key购买 nike

我正在使用第三方库生成 PDF。为了在最后写入 PDF(在使用 lib 的 API 添加所有内容之后),pdfWriter 类型有一个 Write 函数,它需要一个 io.WriteSeeker

如果我想使用文件,这没问题,但我需要在内存中工作。问题是,我找不到任何方法来执行此操作 - 我发现唯一实现 io.WriteSeeker 的 native 类型是 File。

这是通过在 pdfWriter Write 函数中为 io.Writer 使用 File 来工作的部分:

fWrite, err := os.Create(outputPath)
if err != nil {
return err
}

defer fWrite.Close()

err = pdfWriter.Write(fWrite)

有没有办法在没有实际文件的情况下做到这一点?比如获取一个 []byte 之类的东西?

最佳答案

不幸的是,内存中没有现成的解决方案 io.WriteSeeker 在标准库中实现。

但一如既往,您始终可以实现自己的。没那么难。

io.WriteSeeker是一个 io.Writer 和一个 io.Seeker , 所以基本上你只需要实现 2 个方法:

Write(p []byte) (n int, err error)
Seek(offset int64, whence int) (int64, error)

在它们的文档中阅读这些方法的一般契约,它们应该如何表现。

这是一个使用内存字节 slice ([]byte) 的简单实现。它没有针对速度进行优化,这只是一个“演示”实现。

type mywriter struct {
buf []byte
pos int
}

func (m *mywriter) Write(p []byte) (n int, err error) {
minCap := m.pos + len(p)
if minCap > cap(m.buf) { // Make sure buf has enough capacity:
buf2 := make([]byte, len(m.buf), minCap+len(p)) // add some extra
copy(buf2, m.buf)
m.buf = buf2
}
if minCap > len(m.buf) {
m.buf = m.buf[:minCap]
}
copy(m.buf[m.pos:], p)
m.pos += len(p)
return len(p), nil
}

func (m *mywriter) Seek(offset int64, whence int) (int64, error) {
newPos, offs := 0, int(offset)
switch whence {
case io.SeekStart:
newPos = offs
case io.SeekCurrent:
newPos = m.pos + offs
case io.SeekEnd:
newPos = len(m.buf) + offs
}
if newPos < 0 {
return 0, errors.New("negative result pos")
}
m.pos = newPos
return int64(newPos), nil
}

是的,就是这样。

测试它:

my := &mywriter{}
var ws io.WriteSeeker = my

ws.Write([]byte("hello"))
fmt.Println(string(my.buf))

ws.Write([]byte(" world"))
fmt.Println(string(my.buf))

ws.Seek(-2, io.SeekEnd)
ws.Write([]byte("k!"))
fmt.Println(string(my.buf))

ws.Seek(6, io.SeekStart)
ws.Write([]byte("gopher"))
fmt.Println(string(my.buf))

输出(在 Go Playground 上尝试):

hello
hello world
hello work!
hello gopher

可以改进的地方:

  • 创建 mywriter初始为空的值 buf slice ,但其容量很可能覆盖结果 PDF 文档的大小。例如。如果您估计结果 PDF 大约为 1 MB,请创建一个容量为 2 MB 的缓冲区,如下所示:
    my := &mywriter{buf: make([]byte, 0, 2<<20)}

  • 内部 mywriter.Write()当需要增加容量(并且复制现有内容)时,使用更大的增量可能是有利可图的,例如一定程度上将当前容量翻倍,为以后的追加预留空间,最小化重新分配。

关于go - 在 Go 中使用没有文件的 io.WriteSeeker,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45836767/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com