我正在尝试实现代理模式以在io.Reader上进行链式转换,以便有效地处理字节块。
我们不能在接收器上使用指针,所以我的解决方案似乎效率不高
下面的代码说“处理时间太长”
完整示例,位于:https://play.golang.org/p/KhM0VXLq4CO
b := bytes.NewBufferString(text)
t := transformReaderHandler(*b)
readByChunk(t)
type transformReaderHandler bytes.Buffer
func (t transformReaderHandler) Read(p []byte) (n int, err error) {
n, err = (*bytes.Buffer)(&t).Read(p)
//if n > 0 {
// Do Something on the chunk
//}
return
}
您是否有任何更有效的(内存效率高,计算效率高的)解决方案?
为什么此代码不起作用?
编辑: @svsd解决方案的实现:https://play.golang.org/p/VUpJcyKLB6D
package main
import (
"io"
"fmt"
"bytes"
)
const text = "Reaaaaally long and complex text to read in chunk"
func main() {
b := bytes.NewBufferString(text)
t := (*transformReaderHandler)(b)
readByChunk(t)
}
type transformReaderHandler bytes.Buffer
func (t *transformReaderHandler) Read(p []byte) (n int, err error) {
n, err = (*bytes.Buffer)(t).Read(p)
if n > 0 {
p[0] = 'X'
}
return
}
func readByChunk(r io.Reader) {
var p = make([]byte, 4)
for {
n, err := r.Read(p)
if err == io.EOF {
break
}
fmt.Println(string(p[:n]))
}
}
答案 0 :(得分:4)
每次在bytes.Buffer
上调用Read
时,您都将复制transformReaderHandler
值,因此您将永远无法通过缓冲区。您必须使用*bytes.Buffer
指针来避免复制。
在transformReaderHandler
中嵌入缓冲区(或将其添加为命名字段),因此您可以根据需要调用委托Read
方法。
type transformReaderHandler struct {
*bytes.Buffer
}
func (t *transformReaderHandler) Read(p []byte) (n int, err error) {
n, err = t.Buffer.Read(p)
//if n > 0 {
// Do Something
//}
return
}
答案 1 :(得分:2)
下面的代码说“处理时间太长”
为什么此代码不起作用?
在transformReaderHandler.Read()
方法中,您有一个值接收者。这意味着每次调用Read()
时,它都会得到调用它的实例的副本。然后,当您再调用(*bytes.Buffer)(&t).Read(p)
时,它将修改该实例的内部状态,以便下次阅读时,它将从先前读取的位置开始读取。
现在,因为该实例是一个副本,所以在方法退出并且原始实例保持不变之后,它将被丢弃。因此,每次调用Read()
时,bytes.Buffer.Read()
仅读取前几个字节。为了证明这一点,请在调用fmt.Println("n=", n, "err=", err)
之后在readByChunk()
内添加一个语句Read()
。
要快速检查这确实是由于值接收器引起的,可以使用指针接收器定义transformReaderHandler.Read()
并将t
存储为t = (*transformReaderHandler)(b)
。我让您检查一下它的作用。 (编辑:注释中包含嵌入的正确解决方案)
您是否有任何更有效的(内存效率高,计算效率高的)解决方案?
如果您只想寻找缓冲的IO以获得更有效的读取,请查看bufio.NewReader()
。如果这还不够的话,您可以从中获得启发并环绕io.Reader
接口,而不是环绕bytes.Buffer
实例。