go - 以 gzip 格式写入数据的正确方法是什么?
问题描述
我的应用程序产生了大量的文本数据,为了减少磁盘消耗我想以 gzip 格式写入数据
许多 goroutine 同时调用 WriteData() 函数。
但是 linux gzip 抱怨文件损坏。
zcat ./2021-08-11-00.gz > /dev/null
gzip: ./2021-08-11-00.gz: invalid compressed data--format violated
它不是每次都发生,而是几乎每个第二次写入的文件都发生。
我的代码有什么问题?
我的 DataWrite 包看起来像
package storage
import (
"compress/gzip"
"os"
"sync"
"github.com/rs/zerolog/log"
)
type Storage struct {
handle *os.File
writer *gzip.Writer
lock sync.Mutex
}
func (s *Storage) Init(filename string) error {
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
s.handle = file
s.writer = gzip.NewWriter(file)
return nil
}
func (s *Storage) Shutdown() {
if err := s.writer.Close(); err != nil {
log.Warn().Err(err).Msg("Gzip writer close failed")
}
if err := s.handle.Close(); err != nil {
log.Warn().Err(err).Msg("Gzip handle close failed")
}
}
func (s *Storage) WriteData(data *MyStruct) error {
s.lock.Lock()
defer s.lock.Unlock()
buffer := data.content
_, err := s.writer.Write([]byte(buffer))
if err != nil {
log.Warn().Err(err).Msg("Gzip write failed")
return err
}
if err := s.writer.Flush(); err != nil {
return err
}
if err := s.handle.Sync(); err != nil {
return err
}
return nil
}
解决方案
您没有同步关机和写入。
package storage
type Storage struct {
handle *os.File
writer *gzip.Writer
lock sync.Mutex
}
func (s *Storage) Init(filename string) {
file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
return err
}
s.handle = file
s.writer = gzip.NewWriter(file)
}
func (s *Storage) Shutdown() {
s.lock.Lock() // Here !!
defer s.lock.Unlock()
if err := s.writer.Close(); err != nil {
log.Warn().Err(err).Str("fileName", path).Msg("Gzip writer close failed")
}
if err := s.handle.Close(); err != nil {
log.Warn().Err(err).Str("fileName", path).Msg("Gzip handle close failed")
}
}
func (s *Storage) WriteData(data *MyStruct) error {
s.lock.Lock()
defer s.lock.Unlock()
cnt, err := s.writer.Write([]byte(buffer))
if err != nil {
log.Warn().Err(err).Msg("Gzip write failed")
return err
}
if err := s.writer.Flush(); err != nil {
return err
}
if err := s.handle.Sync(); err != nil {
return err
}
return nil
}
推荐阅读
- laravel - 使用 GitHub 将 Laravel 部署到 azure windows web 应用程序会出现错误,需要 ext-fileinfo * -> 您的系统中缺少它
- ruby-on-rails - 是否可以在子类上获取超类和子类属性?
- powershell - ls -a 命令在我的 VS Code 终端上不起作用
- c# - Azure 服务总线订阅指标
- azure - 结合 2 个 ARM 模板(Action Group 和 Budget Alert)
- here-api - 在 HERE sdk 中交换手势
- curl - Ansible Playbook 中的 Curl -F 选项
- javascript - “官方” useInterval 示例中的潜在错误
- reactjs - 通过 props 传递的组件的 React 和 TypeScript 使用
- .net - 在 DbContextOptions 中找不到 ApplicationDbContext