bytes.Buffer的限制?

时间:2013-10-07 15:54:59

标签: go

我正在尝试使用“compress / gzip”包来gzip一片字节。我正在写一个bytes.Buffer,我正在写45976字节,当我尝试使用gzip.reader和读取器函数解压缩内容时 - 我发现并非所有内容都被恢复。 bytes.buffer有一些限制吗?这是通过或改变这种方式的方法吗?这是我的代码(编辑):

func compress_and_uncompress() {
    var buf bytes.Buffer
    w := gzip.NewWriter(&buf)
    i,err := w.Write([]byte(long_string))
    if(err!=nil){
            log.Fatal(err)
    }
    w.Close()

    b2 := make([]byte, 80000)
    r, _ := gzip.NewReader(&buf)
    j, err := r.Read(b2)
    if(err!=nil){
            log.Fatal(err)
    }
    r.Close()

    fmt.Println("Wrote:", i, "Read:", j)
}

测试输出(选择字符串为long_string)会给出 写道:45976,阅读32768

3 个答案:

答案 0 :(得分:5)

继续阅读以获得剩余的13208个字节。第一个读取返回32768个字节,第二个读取返回13208个字节,第三个读取返回零个字节和EOF。

例如,

package main

import (
    "bytes"
    "compress/gzip"
    "fmt"
    "io"
    "log"
)

func compress_and_uncompress() {
    var buf bytes.Buffer
    w := gzip.NewWriter(&buf)
    i, err := w.Write([]byte(long_string))
    if err != nil {
        log.Fatal(err)
    }
    w.Close()

    b2 := make([]byte, 80000)
    r, _ := gzip.NewReader(&buf)
    j := 0
    for {
        n, err := r.Read(b2[:cap(b2)])
        b2 = b2[:n]
        j += n
        if err != nil {
            if err != io.EOF {
                log.Fatal(err)
            }
            if n == 0 {
                break
            }
        }
        fmt.Println(len(b2))
    }
    r.Close()

    fmt.Println("Wrote:", i, "Read:", j)
}

var long_string string

func main() {
    long_string = string(make([]byte, 45976))
    compress_and_uncompress()
}

输出:

32768
13208
Wrote: 45976 Read: 45976

答案 1 :(得分:2)

使用ioutil.ReadAll。 io.Reader的合同说它不必返回所有数据,并且有充分的理由不与内部缓冲区的大小有关。 ioutil.ReadAll的作用类似于io.Reader,但会读到EOF。

例如(未经测试)

import "io/ioutil"

func compress_and_uncompress() {
    var buf bytes.Buffer
    w := gzip.NewWriter(&buf)
    i,err := w.Write([]byte(long_string))
    if err!=nil {
            log.Fatal(err)
    }
    w.Close()

    r, _ := gzip.NewReader(&buf)
    b2, err := ioutil.ReadAll(r)
    if err!=nil {
            log.Fatal(err)
    }
    r.Close()

    fmt.Println("Wrote:", i, "Read:", len(b2))
}

答案 2 :(得分:1)

如果从gzip.NewReader读取的内容未返回整个预期的切片。您可以继续重新阅读,直到您收到缓冲区中的所有数据。

关于你的问题,如果你重新读取后续的读取没有附加到切片的末尾,而是在开头;答案可以在gzip的Read函数的实现中找到,其中包括

208     z.digest.Write(p[0:n])

这将导致字符串开头的“追加”。

这可以通过这种方式解决

func compress_and_uncompress(long_string string) {
    // Writer
    var buf bytes.Buffer
    w := gzip.NewWriter(&buf)
    i,err := w.Write([]byte(long_string))
    if(err!=nil){
            log.Fatal(err)
    }
    w.Close()

    // Reader
    var j, k int
    b2 := make([]byte, 80000)
    r, _ := gzip.NewReader(&buf)
    for j=0 ; ; j+=k {
        k, err = r.Read(b2[j:])  // Add the offset here
        if(err!=nil){
            if(err != io.EOF){
                log.Fatal(err)
            } else{
                break
            }
        }
    }
    r.Close()

    fmt.Println("Wrote:", i, "Read:", j)
}

结果将是:

Wrote: 45976 Read: 45976

在使用45976个字符串进行测试后,我可以确认输出与输入完全相同,其中第二部分正确地附加在第一部分之后。


gzip的来源。阅读:http://golang.org/src/pkg/compress/gzip/gunzip.go?s=4633:4683#L189