首页 > 解决方案 > 在 Go 中使用 struct 更新 mmap 文件

问题描述

类似于将结构写入映射内存文件(mmap),如何在 Go 中将结构写入 mmap 文件或使用 struct 更新 mmap 文件?

假设我的二进制文件以二进制标头开头

type MVHD struct {
    Version      byte
    Flags        [3]byte
    DateCreated  time.Time
    DateModified time.Time

    TimeUnit        uint32 // time unit per second (default = 600)
    DurationInUnits uint64 // time length (in time units)

    Raw []byte // undecoded data after decoded bits above
}

假设我想将其映射为内存文件并更新DateModified字段,这可能吗?

(我在 Go 中对 mmap 的有限阅读是它只能通过字节数组访问,但我确信有一种方法可以通过 struct 访问它。我在这里找到了一个使用reflect但它对我来说太复杂了,无法掌握基本知识主意)

标签: filegostructupdatesmmap

解决方案


您可以使用encoding/binary读取/写入固定大小的结构。这种方法是可移植的,不依赖于内存布局、编译器或 CPU 架构。例如:

// Note: using uint32 instead of time.Time for decoding.
// Convert to time.Time afterwards if needed.
type MVHD struct {
    Version          byte
    Flags            [3]byte
    DateCreatedSecs  uint32
    DateModifiedSecs uint32

    TimeUnit        uint32 // time unit per second (default = 600)
    DurationInUnits uint64 // time length (in time units)
}

// ..or use binary.BigEndian - whichever is correct for your data.
var endian = binary.LittleEndian

func decode(rd io.Reader) (*MVHD, error) {
    var header MVHD 
    if err := binary.Read(rd, endian, &header); err != nil {
        return nil, err
    }
    return &header, nil
}      

用于bytes.NewReader将 a[]byte转换为io.Reader. 这将允许您使用decodemmap 数据。

或者,您可以手动对其进行解码:

func decode2(buf []byte) (*MVHD, error) {
    if len(buf) < 24 {
        return nil, errors.New("not enough data")
    }  
    return &MVHD{
        Version:          buf[0],
        Flags:            [3]byte{buf[1], buf[2], buf[3]},
        DateCreatedSecs:  binary.LittleEndian.Uint32(buf[4:8]),
        DateModifiedSecs: binary.LittleEndian.Uint32(buf[8:12]),
        TimeUnit:         binary.LittleEndian.Uint32(buf[12:16]),
        DurationInUnits:  binary.LittleEndian.Uint64(buf[16:24]),
    }, nil
}

同样,您可以通过调用更新数据:binary.ByteOrder Put

func updateDateModified(buf []byte, t uint32) error {
    if len(buf) < 12 {
        return errors.New("not enough data")
    }
    binary.LittleEndian.PutUint32(buf[8:12], t)
    return nil
}

推荐阅读