您的代码中有很多错误。
作为“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() 也会刷新,因此这似乎是一个不必要的步骤,但必须这样做,例如,如果 gzip.Writer 的 Close() 也被称为延迟语句,因为那样它可能不会在我们之前执行使用缓冲区的内容。因为在我们的示例中,我们在io.Copy() 之后关闭了 gzip 编写器,这将处理必要的刷新。
接下来,要替换原始文件的内容,必须回溯到要替换的文件开头。为此,您可以使用File.Seek()。
接下来,您可以再次使用io.Copy() 将缓冲区的内容(压缩后的数据)复制到文件中。
最后,由于 gzip 压缩的内容很可能比原始文件的大小短,因此您必须按照 gzip 内容的大小截断文件(否则原始文件的未压缩内容可能会保留在那里)。
这是完整的代码:
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)
}
}
注意:以上代码将替换您磁盘上的文件内容。如果你不想要这个并且你只需要压缩数据,你可以这样做。请注意,我使用了io.Reader 类型的新input 变量,因为bytes.Buffer(或*bytes.Buffer)的值不能分配给*os.File 类型的变量,我们很可能只需要结果作为io.Reader 的值(这由两者实现):
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
注意 #2: 如果您不想“处理”压缩数据,但只想发送它,例如作为网络响应,您甚至不需要bytes.Buffer,您只需将压缩数据“流式传输”到http.ResponseWriter。
它可能看起来像这样:
func myHandler(w http.ResponseWriter, r *http.Request) {
file, err := os.Open(fileName)
if err != nil {
http.NotFound(w, r)
}
defer file.Close()
gz := gzip.NewWriter(w)
defer gz.Close()
if _, err := io.Copy(gz, file); err != nil {
// handle error
}
}
将自动检测并设置正确的内容类型。