【问题标题】:golang zlib reader output not being copied over to stdoutgolang zlib 阅读器输出没有被复制到标准输出
【发布时间】:2015-12-22 15:29:36
【问题描述】:

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

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

代码没有错误,但它也没有按照我的预期做;也就是将解压后的文件内容显示到标准输出中。

另外:除了使用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
        }
    }

【问题讨论】:

    标签: go zlib


    【解决方案1】:

    您的 defer 函数没有做任何事情,因为您在每次新分配时都隐藏了 err 变量。如果要运行 defer,请从单独的函数返回,并在 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()
    

    【讨论】:

      【解决方案2】:

      我认为你用所有这些 defer 的东西和你的“诡计”错误检查搞砸了代码逻辑。

      文件在刷新或关闭时被明确写入。您只需复制到 new.txt 中,打开它阅读它之前不关闭它。

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

      顺便说一句:你对 log.Fatal 终止代码而不调用你的 defers 的防御是,嗯,至少很奇怪。这些文件都由操作系统设置为适当的状态,完全没有必要像这样复杂化。

      【讨论】:

        【解决方案3】:

        检查第二个Copy的错误:

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

        问题是,你需要在写完之后立即关闭zdest。在第一个 Copy 之后关闭它,它就可以工作了。

        【讨论】:

          【解决方案4】:

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

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

          【讨论】:

            猜你喜欢
            • 2021-10-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-06-27
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多