【问题标题】:limitation on bytes.Buffer?bytes.Buffer 的限制?
【发布时间】:2013-10-07 15:54:58
【问题描述】:

我正在尝试使用包“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)会给出 写:45976,读 32768

【问题讨论】:

  • 根据文档:golang.org/pkg/bytes/#Buffer,如果缓冲区无法增长,它将出现恐慌。你 100% 确定你的代码吗?
  • 如果您没有提供代码示例来修复,您希望 SO 人群提供什么样的修复?
  • 对此感到抱歉。我已经编辑了我的问题,还包含了一个代码 sn-p。

标签: go


【解决方案1】:

继续阅读以获取剩余的 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

【讨论】:

  • 嗯,这不需要“丑陋”的黑客攻击吗?我正在考虑一个 while 循环,它会一直读取直到读取的字节数等于写入缓冲区的字节数。
  • 我觉得和我自己的差不多(我也试过你的),long_string的最后一个内容部分先附加到b2。
  • 看看我修改后的答案。我调整了b2 的大小。
【解决方案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))
}

【讨论】:

    【解决方案3】:

    如果从 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-12-22
      • 2018-12-27
      • 2013-11-07
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多