首页 > 解决方案 > 以 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
}

标签: gogzip

解决方案


您没有同步关机和写入。

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
}

推荐阅读