golang zlib reader 输出未被复制到标准输出

golang zlib reader output not being copied over to stdout

我修改了 zlib 包的官方文档示例,以使用打开的文件而不是一组硬编码字节(代码如下)。

代码读取源文本文件的内容并使用 zlib 包对其进行压缩。然后我尝试读回压缩文件并将其解压缩的内容打印到标准输出中。

代码没有错误,但也没有达到我的预期;这是将解压后的文件内容显示到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("\nDeferred log: \n", 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
        }
    }

我认为你用这些 defer 东西和你的 "trick" 错误检查搞乱了代码逻辑。

文件在刷新或关闭时明确写入。您只需复制到 new.txt 而无需关闭 ,然后 打开它进行阅读。

在有多个出口的函数中延迟关闭文件是很巧妙的:它确保一旦函数离开就关闭文件。但是您的 main 要求 new.txt 在复制后关闭,然后再重新打开它。所以不要在这里推迟收盘。

顺便说一句:您对 log.Fatal 终止代码而不调用延迟的防御至少很奇怪。这些文件都被 OS 置于适当的状态,完全没有必要像这样复杂化这些东西。

您的 defer func 不执行任何操作,因为您在每次新赋值时都隐藏了 err 变量。如果你想要一个 defer 到 运行,return 来自一个单独的函数,并在 return 语句之后调用 log.Fatal

至于为什么您没有看到任何输出,这是因为您推迟了所有 Close 调用。 zlib.Writer 直到函数退出后才会刷新,目标文件也不会刷新。在需要的地方显式调用 Close()

zdest := zlib.NewWriter(dest)

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

检查第二个错误Copy:

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

问题是,您需要在完成写入后立即关闭 zdest。在第一个 Copy 之后关闭它并且它有效。

我建议使用 io.MultiWriter。 这样你只从 src 读取一次。小文件的增益不大,但大文件的速度更快。

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