我有以下Go代码:
file, err := os.Open(fileName)
if err != nil {
fatalf(service, "Error opening %q: %v", fileName, err)
}
// Check if gzip should be applied
if *metaGzip == true {
var b bytes.Buffer
w := gzip.NewWriter(&b)
w.Write(file)
w.Close()
file = w
}
如果file
,我想用gzip压缩版本替换metaGzip = true
的文件内容。
PS:
我遵循了这个建议:Getting "bytes.Buffer does not implement io.Writer" error message但我仍然收到错误:cannot use file (type *os.File) as type []byte in argument to w.Write
答案 0 :(得分:2)
您的代码中存在很多错误。
作为“pre-first”,请务必检查返回的错误!
首先,os.Open()
以只读模式打开文件。要能够替换磁盘上的文件内容,必须改为以读写模式打开它:
file, err := os.OpenFile(fileName, os.O_RDWR, 0)
接下来,当您打开io.Closer
(*os.File
为io.Closer
)的内容时,请确保使用Close()
方法关闭它,最好以延期陈述。
接下来,*os.File
是io.Reader
,但这与字节切片[]byte
不同。 io.Reader
可用于将字节读入字节片。使用io.Copy()
将文件中的内容复制到gzip流(最终将在缓冲区中)。
在某些情况下(您不关闭gzip.Writer
),您必须调用gzip.Writer.Flush()
以确保所有内容都刷新到其编写器(在这种情况下是缓冲区)。请注意,gzip.Writer.Close()
也会刷新,因此这似乎是一个不必要的步骤,但必须完成,例如Close()
的{{1}}也被称为延迟状态,因为它在我们使用缓冲区的内容之前可能不会执行。因为在我们的考试中,我们在gzip.Writer
之后关闭了gzip编写器,这将处理必要的刷新。
接下来,要替换原始文件的内容,必须回到要替换的文件的开头。为此,您可以使用File.Seek()
。
接下来,您可以再次使用io.Copy()
将缓冲区的内容(gzip压缩数据)复制到文件中。
最后,由于gzip压缩内容很可能比原始文件大小短,因此必须按照gzip压缩内容的大小截断文件(否则原始文件的未压缩内容可能会留在那里)。
这是完整的代码:
io.Copy()
注意:以上代码将替换磁盘上的文件内容。如果你不想要这个并且你只需要压缩数据,你可以这样做。请注意,我使用了file, err := os.OpenFile(fileName, os.O_RDWR, 0)
if err != nil {
log.Fatalf("Error opening %q: %v", fileName, err)
}
defer file.Close()
// Check if gzip should be applied
if *metaGzip {
var b = &bytes.Buffer{}
w := gzip.NewWriter(b)
if _, err := io.Copy(w, file); err != nil {
panic(err)
}
if err := w.Close(); err != nil { // This also flushes
panic(err)
}
if _, err := file.Seek(0, 0); err != nil {
panic(err)
}
if _, err := io.Copy(file, b); err != nil {
panic(err)
}
if err := file.Truncate(int64(b.Len())); err != nil {
panic(err)
}
}
类型的新input
变量,因为io.Reader
(或bytes.Buffer
)的值无法分配给*bytes.Buffer
类型的变量,我们很可能只需要将结果作为*os.File
的值(这由两者实现):
io.Reader
注意#2:如果您不想“处理”压缩数据,但您只想发送它,例如作为网络响应,您甚至不需要bytes.Buffer
,您只需将压缩数据“流式传输”到http.ResponseWriter
。
看起来像这样:
var input io.Reader
file, err := os.Open(fileName)
if err != nil {
log.Fatalf("Error opening %q: %v", fileName, err)
}
defer file.Close()
// Check if gzip should be applied
if *metaGzip {
var b = &bytes.Buffer{}
w := gzip.NewWriter(b)
if _, err := io.Copy(w, file); err != nil {
panic(err)
}
if err := w.Close(); err != nil { // This also flushes
panic(err)
}
input = b
} else {
input = file
}
// Use input here
将自动检测并设置正确的内容类型。