web-dev-qa-db-ja.com

Golang予期しないEOF

これが私のコードです。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
Dylan

問題の特定のコードでトレースを行った後、私は次の答えに達しました。

/ src/bytes/reader.go 7

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

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

    ....
}

io.EOFを返すことができるバイト/リーダーの4つの関数と、io.ErrUnexpectedEOFを返すことができるゼロの関数があります。 io.EOFを返すことができる4つの関数は次のとおりです。

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を返すことができる4つの関数のうち、flate/inflate.go内の1つの関数だけがそれらの関数を呼び出します。moreBits()ReadByte()を呼び出します

/ src/compress/flate/inflate.go 69

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で確認されました

4
chewbapoclypse

あなたはインとアウトプットを混ぜ合わせました。

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
}
4
RickyA