简体   繁体   English

GoLang 链接 io.Reader

[英]GoLang chaining io.Reader

I'm trying to implement a proxy pattern to chain transformations on io.Reader, in order to handle chunk of bytes efficiently.我正在尝试实现一个代理模式来链接 io.Reader 上的转换,以便有效地处理字节块。

  1. We cannot use pointers on receivers, so my solution seem not very efficient我们不能在接收器上使用指针,所以我的解决方案似乎不是很有效

  2. The code below say "process take too long"下面的代码说“过程花费太长时间”

Complete example at: https://play.golang.org/p/KhM0VXLq4CO完整示例位于: 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
}

Do you have any more efficient (memory efficient, computationally efficient) solution ?你有更高效(内存高效、计算高效)的解决方案吗?

Why do this code is not working ?为什么这段代码不起作用?

EDIT: The implementation of @svsd solution : https://play.golang.org/p/VUpJcyKLB6D编辑:@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]))
    }
}

You're copying the bytes.Buffer value each time Read is called on the transformReaderHandler , so you can never progress through the buffer.每次在transformReaderHandler上调用Read您都在复制bytes.Buffer值,因此您永远无法通过缓冲区。 You must used a *bytes.Buffer pointer to avoid this copy.您必须使用*bytes.Buffer指针来避免此副本。

Embed the buffer (or alternatively add it as a named field) in your transformReaderHandler , so you can call delegate the Read method as needed.在您的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 https://play.golang.org/p/npZQ4Tz0hhv

The code below say "process take too long"下面的代码说“过程花费太长时间”

Why do this code is not working ?为什么这段代码不起作用?

In the transformReaderHandler.Read() method, you have a value receiver.transformReaderHandler.Read()方法中,您有一个值接收器。 That means each time Read() is called, it gets a copy of the instance on which it was called.这意味着每次调用Read() ,它都会获取调用它的实例的副本 Then when you then call (*bytes.Buffer)(&t).Read(p) , it modifies the internal state of that instance so that next time when you read, it reads from after the point it read earlier.然后,当您调用(*bytes.Buffer)(&t).Read(p) ,它会修改该实例的内部状态,以便下次读取时,它会从之前读取的点之后读取。

Now because the instance is a copy, it is discarded after the method exits and the original instance remains unchanged.现在因为实例是副本,所以在方法退出后被丢弃,原始实例保持不变。 Hence, each time you call Read() , bytes.Buffer.Read() reads only the first few bytes.因此,每次调用Read()bytes.Buffer.Read()仅读取前几个字节。 To prove this, add a statement fmt.Println("n=", n, "err=", err) inside readByChunk() after calling Read() .为了证明这一点,在调用Read()之后在readByChunk()添加一条语句fmt.Println("n=", n, "err=", err) Read()

To quickly check that this is indeed due to the value receiver, you can define transformReaderHandler.Read() with a pointer receiver and store t as t = (*transformReaderHandler)(b) .为了快速检查这确实是由于值接收器,您可以使用指针接收器定义transformReaderHandler.Read()并将t存储为t = (*transformReaderHandler)(b) I'll let you examine what it does.我会让你检查它的作用。 (edit: the correct solution involving embedding is in the comments) (编辑:涉及嵌入的正确解决方案在评论中)

Do you have any more efficient (memory efficient, computationally efficient) solution ?你有更高效(内存高效、计算高效)的解决方案吗?

If you're only looking for buffered IO for more efficient reads, look at the bufio.NewReader() .如果您只是在寻找缓冲 IO 以提高读取效率,请查看bufio.NewReader() If that's not sufficient, you can take inspiration from it and wrap around an io.Reader interface instead of wrapping over a bytes.Buffer instance.如果这还不够,您可以从中io.Reader灵感并环绕一个io.Reader接口,而不是环绕一个bytes.Buffer实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM