GoLang链接io.Reader

问题描述 投票:-4回答:2

我正在尝试在io.Reader上实现代理模式链转换,以便有效地处理大块字节。

  1. 我们不能在接收器上使用指针,所以我的解决方案看起来效率不高
  2. 下面的代码说“过程需要太长时间”

完整示例: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]))
    }
}
go
2个回答
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实例上。


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
}

https://play.golang.org/p/npZQ4Tz0hhv

© www.soinside.com 2019 - 2024. All rights reserved.