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)
我修改了 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)