2

我正在尝试使用包“compress/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)将给出 Wrote: 45976, Read 32768

4

3 回答 3

7

继续阅读以获取剩余的 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
于 2013-10-07T16:21:24.537 回答
3

使用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))
}
于 2013-10-08T16:12:16.307 回答
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

于 2013-10-07T21:59:26.513 回答