golang zlib阅读器输出未复制到stdout

I've modified the official documentation example for the zlib package to use an opened file rather than a set of hardcoded bytes (code below).

The code reads in the contents of a source text file and compresses it with the zlib package. I then try to read back the compressed file and print its decompressed contents into stdout.

The code doesn't error, but it also doesn't do what I expect it to do; which is to display the decompressed file contents into stdout.

Also: is there another way of displaying this information, rather than using io.Copy?

    package main

    import (
        "compress/zlib"
        "io"
        "log"
        "os"
    )

    func main() {
        var err error

        // This defends against an error preventing `defer` from being called
        // As log.Fatal otherwise calls `os.Exit`
        defer func() {
            if err != nil {
                log.Fatalln("
Deferred log: 
", err)
            }
        }()

        src, err := os.Open("source.txt")
        if err != nil {
            return
        }
        defer src.Close()

        dest, err := os.Create("new.txt")
        if err != nil {
            return
        }
        defer dest.Close()

        zdest := zlib.NewWriter(dest)
        defer zdest.Close()

        if _, err := io.Copy(zdest, src); err != nil {
            return
        }

        n, err := os.Open("new.txt")
        if err != nil {
            return
        }

        r, err := zlib.NewReader(n)
        if err != nil {
            return
        }
        defer r.Close()
        io.Copy(os.Stdout, r)

        err = os.Remove("new.txt")
        if err != nil {
            return
        }
    }

Your defer func doesn't do anything, because you're shadowing the err variable on every new assignment. If you want a defer to run, return from a separate function, and call log.Fatal after the return statement.

As for why you're not seeing any output, it's because you're deferring all the Close calls. The zlib.Writer isn't flushed until after the function exits, and neither is the destination file. Call Close() explicitly where you need it.

zdest := zlib.NewWriter(dest)

if _, err := io.Copy(zdest, src); err != nil {
    log.Fatal(err)
}
zdest.Close()
dest.Close()

I think you messed up the code logic with all this defer stuff and your "trick" err checking.

Files are definitively written when flushed or closed. You just copy into new.txt without closing it before opening it to read it.

Defering the closing of the file is neat inside a function which has multiple exits: It makes sure the file is closed once the function is left. But your main requires the new.txt to be closed after the copy, before re-opening it. So don't defer the close here.

BTW: Your defense against log.Fatal terminating the code without calling your defers is, well, at least strange. The files are all put into some proper state by the OS, there is absolutely no need to complicate the stuff like this.

Check the error from the second Copy:

2015/12/22 19:00:33 
Deferred log: 
 unexpected EOF
exit status 1

The thing is, you need to close zdest immediately after you've done writing. Close it after the first Copy and it works.

I would have suggested to use io.MultiWriter. In this way you read only once from src. Not much gain for small files but is faster for bigger files.

  w :=  io.MultiWriter(dest, os.Stdout)