在 Go 中使用结构更新 mmap 文件
Updating mmap file with struct in Go
类似于Writing struct to mapped memory file (mmap),如何在Go中将struct写入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 的有限阅读是它只能通过字节数组访问,但我确信有一种方法可以通过结构访问它。我找到了一个 here 使用 reflect
但对我来说太复杂了,无法掌握基本思想)
您可以使用 encoding/binary
到 read/write 固定大小的结构。这种方法是可移植的,不依赖于内存布局、编译器或 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
将 []byte
转换为 io.Reader
。这将允许您将 decode
与 mmap 数据一起使用。
或者,您可以手动解码:
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
}
类似于Writing struct to mapped memory file (mmap),如何在Go中将struct写入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 的有限阅读是它只能通过字节数组访问,但我确信有一种方法可以通过结构访问它。我找到了一个 here 使用 reflect
但对我来说太复杂了,无法掌握基本思想)
您可以使用 encoding/binary
到 read/write 固定大小的结构。这种方法是可移植的,不依赖于内存布局、编译器或 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
将 []byte
转换为 io.Reader
。这将允许您将 decode
与 mmap 数据一起使用。
或者,您可以手动解码:
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
}