【问题标题】:Go: Copy data from io.Reader to io.Writer implementations with sleep timeout, empty WritesGo:将数据从 io.Reader 复制到 io.Writer 实现,休眠超时,空写入
【发布时间】:2022-01-10 21:07:58
【问题描述】:

-编辑-

这不是由拼写错误引起的,它是可重现的,这与 stackoverflow 给出的名称相反。提供的代码是专门为这个问题的独立示例而编写的(问题就在代码中,您所要做的就是运行它来重现问题......)

此外,这是我遇到的确切问题,也是我在提问之前在 StackOverflow 上没有找到的确切解决方案。答案来自 IRC 上的一次对话,我已将解决方案转发给像我这样可能遇到同样问题的其他人。这是一个非常相关的问答,当然可以帮助未来的读者。

谢谢

-编辑-

我正在尝试将数据从 io.Reader 实现复制到 io.Writer 实现,并在下一次迭代之前延迟(time.Sleep)。理想情况下,我想控制该过程(即 io.Copy 并不理想,因为我可能想在读取和写入之间执行一些操作)。

无论如何,在下面的代码中尝试了 4 种方法,它应该在 go.dev/play 中运行。除了空字符串之外,我无法获得任何写入任何内容的方法,尽管所有写入方法确实报告了正确的写入字节数(与读取报告的相同)。我可能遗漏了一些基本的东西,但非常感谢任何帮助/解释,因为我很困惑。

以下代码包含用于 4 种不同方法的 cmets 和函数,用于在下一次迭代之前以指定的延迟 (time.Sleep) 将数据从 io.Reader 的自定义实现复制和记录到 io.Writer。您可以在下面评论/取消评论所需的功能以观察结果。

package main

import (
    "bufio"
    "fmt"
    "io"
    "log"
    "math/rand"
    "time"
)

// READ
type MyReader struct{}

func (r *MyReader) Read(p []byte) (read int, err error) {

    someString := fmt.Sprintf("testing-%d", rand.Int())

    p = []byte(someString)
    read = len(p)

    log.Printf("io read %d bytes: %s\n", read, string(p))

    return read, io.EOF
}

// WRITE
type MyWriter struct{}

func (w *MyWriter) Write(p []byte) (wrote int, err error) {

    wrote = len(p)
    log.Printf("io wrote %d bytes: %s\n", wrote, string(p))

    return
}

// MAIN
func main() {

    // The following contains comments and functions for 4 different approaches to copying and logging data from
    // custom implementations of io.Reader to an io.Writer with a specified delay (time.Sleep) before the next
    // iteration. You may comment/uncomment the desired function below to observe the results.

    // AutoIoCopy - Approach 1) io.Copy
    //
    // Expected is to read and log the correct value (generated in the method)
    // then write the value (output another log)
    //
    // Actual is that the bufio.Write method is called and the MyWriter.Write method of the io.Writer implementation
    // is executed, but the output logged by MyWriter.Write is empty instead of the expected string reported by the
    // MyReader.Read log.
    //
    AutoIoCopy()

    // ReadBytesApproach - Approach 2) Using ReadBytes('\n')
    //
    // Expected is to read and log the correct value (generated in the method)
    // then write the value (output another log)
    //
    // Actual is that the bufio.Write method is called and reports written bytes, but the Write method of MyWriter
    // io.Writer implementation is never executed, it is skipped and another Read occurs
    //
    //ReadBytesApproach()

    // ReadLineApproach - Approach 3) Using ReadLine()
    //
    // Expected is to read and log the correct value (generated in the method)
    // then write the value (output another log)
    //
    // Actual is that the bufio.Write method is called and reports written bytes, but the Write method of MyWriter
    // io.Writer implementation is never executed, it is skipped and another Read occurs
    //
    //ReadLineApproach()

    // WriteToApproach - Approach 4) Using WriteTo()
    //
    // Expected is to read and log the correct value (generated in the method)
    // then write the value (output another log)
    //
    // Actual is that the bufio.Write method is called and reports written bytes, but the Write method of MyWriter
    // io.Writer implementation is never executed, it is skipped and another Read occurs
    //
    //WriteToApproach()

}

// Approaches:

// AutoIoCopy - Approach 1) io.Copy
//
// Expected is to read and log the correct value (generated in the method)
// then write the value (output another log)
//
// Actual is that the bufio.Write method is called and the MyWriter.Write method of the io.Writer implementation
// is executed, but the output logged by MyWriter.Write is empty instead of the expected string reported by the
// MyReader.Read log.
//
func AutoIoCopy() {

    reader := MyReader{}
    writer := MyWriter{}

    for {
        _, _ = io.Copy(&writer, &reader)
        time.Sleep(1000 * time.Millisecond)
    }
}

// ReadBytesApproach - Approach 2) Using ReadBytes('\n')
//
// Expected is to read and log the correct value (generated in the method)
// then write the value (output another log)
//
// Actual is that the bufio.Write method is called but the Write method of MyWriter io.Writer implementation
// is never executed, it is skipped and another Read occurs
//
func ReadBytesApproach() {

    reader := MyReader{}
    writer := MyWriter{}

    bufRead := bufio.NewReader(&reader)
    bufWrite := bufio.NewWriter(&writer)

    for {

        // Using ReadBytes('\n')
        readBytes, err := bufRead.ReadBytes('\n')

        if err != nil {

            switch err {
            case io.EOF:

                log.Printf("io.EOF detected\n")
                wrote, err := bufWrite.Write(readBytes)
                if err != nil {
                    log.Printf("error writing: %s\n", err)
                }
                convertedValue := string(readBytes)
                log.Printf("bufio wrote %d bytes: %s\n", wrote, convertedValue)
                break

            default:
                log.Printf("bufio error reading: %s\n", err.Error())
                break
            }

        } else {
            log.Printf("no error, continue to read\n")
        }

        time.Sleep(1000 * time.Millisecond)
    }
}

// ReadLineApproach - Approach 3) Using ReadLine()
//
// Expected is to read and log the correct value (generated in the method)
// then write the value (output another log)
//
// Actual is that the bufio.Write method is called but the Write method of MyWriter io.Writer implementation
// is never executed, it is skipped and another Read occurs
//
func ReadLineApproach() {

    reader := MyReader{}
    writer := MyWriter{}

    bufRead := bufio.NewReader(&reader)
    bufWrite := bufio.NewWriter(&writer)

    for {

        // Using ReadLine()
        readBytes, _, err := bufRead.ReadLine()

        if err != nil {

            switch err {
            case io.EOF:

                log.Printf("io.EOF detected\n")
                wrote, err := bufWrite.Write(readBytes)
                if err != nil {
                    log.Printf("error writing: %s\n", err)
                }
                convertedValue := string(readBytes)
                log.Printf("bufio wrote %d bytes: %s\n", wrote, convertedValue)
                break

            default:
                log.Printf("bufio error reading: %s\n", err.Error())
                break
            }

        } else {
            log.Printf("no error, continue to read\n")
        }

        time.Sleep(1000 * time.Millisecond)
    }

}

// WriteToApproach - Approach 4) Using WriteTo()
//
// Expected is to read and log the correct value (generated in the method)
// then write the value (output another log)
//
// Actual is that neither the bufio.Write or the Write method of MyWriter io.Writer implementation is executed,
// it is skipped and another Read occurs
//
func WriteToApproach() {

    reader := MyReader{}
    writer := MyWriter{}

    bufRead := bufio.NewReader(&reader)
    bufWrite := bufio.NewWriter(&writer)

    for {
        wrote, _ := bufRead.WriteTo(bufWrite)
        log.Printf("bufio wrote %d bytes\n", wrote)
        time.Sleep(1000 * time.Millisecond)
    }
}

【问题讨论】:

  • 我对 Go 没有太多经验,但看起来应该重新打开它

标签: go io


【解决方案1】:

问题出在MyReader.Read 方法中

线

p = []byte(someString)

应该是

read = copy(p, someString)

【讨论】:

    猜你喜欢
    • 2018-04-16
    • 2018-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多