【问题标题】:Golang unexpected EOFGolang 意外的 EOF
【发布时间】:2018-06-29 16:13:33
【问题描述】:

这是我的代码,我是 Go 新手。 我试着用谷歌搜索这个问题,但我不能完全解决这个问题。 我认为这与Read() 方法有关。

package main

import (
    ...
)

type compressor struct {
    content []byte
}

func (r *compressor) compress() []byte {
    ...
}

func (r *compressor) decompress() []byte {
    var buffer bytes.Buffer
    dc := flate.NewReader(&buffer)
    _, err := dc.Read(r.content)
    if err != nil {
        if err != io.EOF {
            log.Fatal(err)
        }
    }

    return buffer.Bytes()
}

func main() {
    fileName := os.Args[1]
    fmt.Println(os.Args)
    contents, err := ioutil.ReadFile(fileName)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Print("Uncompressed data: ")
    fmt.Println(len(contents))

    comp := compressor{contents}
    buffer := comp.decompress()
    fmt.Print("Uncompressed data: ")
    fmt.Println(len(comp.decompress()))

    err = ioutil.WriteFile(fileName+".decjc", buffer, 0644)
    if err != nil {
        log.Fatal(err)
    }
}

这是输出

dylan@skynet:~/Documents/EXP/jc$ ./jc data.txt.jc 
[./jc data.txt.jc]
Uncompressed data: 2364480
2018/06/29 21:41:35 unexpected EOF

【问题讨论】:

  • 抛出的错误在哪里?什么线路?
  • 你正在从一个空缓冲区读取,所以没有什么可以解压缩的。
  • 也许你在decompress() 中的第一行你的意思是bytes.NewReader(r.content)
  • @Dylan:不,它没有。您正在阅读 buffer,这是一个 bytes.Buffer,您从未将任何数据放入其中。
  • 请看一下这个 Github 问题评论:github.com/revel/revel/issues/566#issuecomment-42019967

标签: go eof inflate


【解决方案1】:

在对有问题的特定代码进行跟踪之后,我得出了以下答案。

/src/bytes/reader.go 70

func (r *Reader) ReadByte() (byte, error) {
    ...

    if r.i >= int64(len(r.s)) {
        return 0, io.EOF
    }

    ....
}

bytes/reader 中有四个函数可以返回io.EOF,零个函数可以返回io.ErrUnexpectedEOF。可以返回io.EOF的四个函数分别是:

Read(b []byte)
ReadAt(b []byte, off int64)
ReadByte()
ReadRune()

/src/compress/flate/inflate.go 698

func (f *decompressor) moreBits() error {
    c, err := f.r.ReadByte()
    if err != nil {
        return noEOF(err)
    }

    ...
}

在可以返回io.EOF的四个函数中,flate/inflate.go中只有一个函数调用了它们中的任何一个:moreBits()调用ReadByte()

/src/compress/flate/inflate.go 690

func noEOF(e error) error {
    if e == io.EOF {
        return io.ErrUnexpectedEOF
    }

    ...
}

moreBits() 收到错误时,它会调用noEOF(),它会检查它是否收到了io.EOF。如果是这种情况,则返回支持 io.ErrUnexpectedEOF。一切似乎都按预期工作,并且用户似乎有责任留意这种特殊情况。建议对上述代码进行编辑以处理看似已定义的行为:

func (r *compressor) decompress() []byte {
    dc := flate.NewReader(bytes.NewReader(r.content))
    defer dc.Close()
    rb, err := ioutil.ReadAll(dc)
    if err != nil {
        if err != io.EOF && err != io.ErrUnexpectedEOF {
            log.Fatalf("Err %v\n read %v", err, rb)
        }
    }
    return rb
}

这是在go1.12.9下检查的

【讨论】:

  • 我在测试中遇到了这个问题,您的解决方案在那里有效。不过,我认为这是不对的,但对于测试,我可以有一些这样的 hack。
【解决方案2】:

你把输入和输出搞混了。

flate.NewReader 将压缩后的输入作为io.Reader 并返回一个io.ReadCloser 可用于获取未压缩的输出:

func (r *compressor) decompress() []byte {
    dc := flate.NewReader(bytes.NewReader(r.content))
    defer dc.Close()
    rb, err := ioutil.ReadAll(dc)
    if err != nil {
        if err != io.EOF {
            log.Fatalf("Err %v\n read %v", err, rb)
        }
    }
    return rb
}

【讨论】:

  • 读入一个空字节片是徒劳的。您可能是指 ioutil.ReadAll 左右。
  • 我发现另一件事是压缩时编码出现问题。因此,在解压缩其中一个字节时,会被解码为 EOF。
  • 请注意,compress/flate 不会解压缩 gzip 文件。有compress/gzip
猜你喜欢
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-08
相关资源
最近更新 更多