Golang遇到意外的EOF错误。

16

这是我的代码,我刚学习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

4
你正在读取一个空缓冲区,因此没有内容可供解压缩。 - JimB
1
也许你在 decompress() 函数的第一行想要写成 bytes.NewReader(r.content) - k1m190r
2
@Dylan:不是的。你正在从buffer中读取,而这是一个bytes.Buffer,你从未向其中放入任何数据。 - JimB
1
请查看此Github问题评论:https://github.com/revel/revel/issues/566#issuecomment-42019967 - andy
@andy:谢谢!我也遇到了同样的问题,你提供的评论是真正的解决方案。 - Khoi
显示剩余3条评论
2个回答

11

经过对特定代码的跟踪,我得出了以下答案。

/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 版本下检查的。


我在一次测试中遇到了这个问题,你的解决方案在那里起作用了。虽然我认为它不完全正确,但是在一个测试中,我可以使用一些像这样的技巧。 - Alexis Wilke

4
你把输入和输出搞混了。 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
}

1
读取空字节切片是徒劳的。你可能想使用ioutil.ReadAll或类似的函数。 - Peter
另一件事是,我发现在压缩时编码出了问题。因此,在解压缩时,其中一个字节被解码为EOF。 - Dylan
1
请注意,compress/flate 不能解压缩gzip文件。而是需要使用 compress/gzip 来进行解压缩。 - RickyA

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接