如何通过通道传递压缩字节?

时间:2013-05-21 00:48:01

标签: go channel

我正在尝试从缓冲读取器压缩文件并通过字节通道传递压缩字节,但效果不佳:),这就是我到现在为止所发现的,显然这不起作用......

func Compress(r io.Reader) (<-chan byte) {
    c := make(chan byte)
    go func(){
        var wBuff bytes.Buffer
        rBuff := make([]byte, 1024)
        writer := zlib.NewWriter(*wBuff)
        for {
            n, err := r.Read(rBuff)
            if err != nil && err != io.EOF { panic(err) }
            if n == 0 { break }
            writer.Write(rBuff) // Compress and write compressed data
            // How to send written compressed bytes through channel?
            // as fas as I understand wBuff will eventually contain
            // whole compressed data?
        }
        writer.Close()
        close(c) // Indicate that no more data follows
    }()
    return c
}

请耐心等待我,因为我是Go的新手

4 个答案:

答案 0 :(得分:2)

我建议使用[]byte代替byte。它更有效率。由于并发内存访问,可能需要通过通道发送缓冲区的副本,而不是自己发送[]byte缓冲区。

您可以定义type ChanWriter chan []byte并让它实现io.Writer接口。然后将ChanWriter传递给zlib.NewWriter

您可以创建一个goroutine来进行压缩,然后立即从ChanWriter函数返回Compress的频道。如果没有goroutine,那么函数没有理由返回一个频道,首选的返回类型是io.Reader

Compress函数的返回类型应更改为chan <-BytesWithError之类的内容。在这种情况下,ChanWriter可以定义为type ChanWriter chan BytesWithError

答案 1 :(得分:1)

您的writer.Write(rBuff)语句始终写入len(rBuff)个字节,即使n != len(rBuff)也是如此。

writer.Write(rBuff[:n])

此外,您的Read循环

for {
    n, err := r.Read(rBuff)
    if err != nil && err != io.EOF {
        panic(err)
    }
    if n == 0 {
        break
    }
    writer.Write(rBuff[:n])
    // ...
}

相当于

for {
    n, err := r.Read(rBuff)
    if err != nil && err != io.EOF {
        panic(err)
    }
    // !(err != nil && err != io.EOF)
    // !(err != nil) || !(err != io.EOF)
    // err == nil || err == io.EOF
    if err == nil || err == io.EOF {
        if n == 0 {
            break
        }
    }
    writer.Write(rBuff[:n])
    // ...
}

循环过早退出if err == nil && if n == 0

相反,写一下

for {
    n, err := r.Read(rBuf)
    if err != nil {
        if err != io.EOF {
            panic(err)
        }
        if n == 0 {
            break
        }
    }
    writer.Write(rBuf[:n])
    // ...
}

答案 2 :(得分:1)

沿着通道逐个发送字节不会特别有效。另一种可能更有用的方法是返回实现io.Reader接口的对象,通过从原始Read()读取块并在返回之前压缩其输出来实现io.Reader方法。

答案 3 :(得分:0)

好的,我找到了有效的解决方案:(随意指出可以改进的地方,或者我做错了什么?)

func Compress(r io.Reader) (<-chan byte) {
    c := make(chan byte)

    go func(){
        var wBuff bytes.Buffer
        rBuff := make([]byte, 1024)
        writer := zlib.NewWriter(&wBuff)
        for {
            n, err := r.Read(rBuff)

            if err != nil {
                if err != io.EOF {
                    panic(err)
                }
                if n == 0 {
                    break
                }
            }

            writer.Write(rBuff[:n])

            for _, v := range wBuff.Bytes() {
                c <- v
            }

            wBuff.Truncate(0)
        }

        writer.Close()

        for _, v := range wBuff.Bytes() {
            c <- v
        }

        close(c) // Indicate that no more data follows
    }()

    return c
}