英文:
Updating mmap file with struct in Go
问题
与 https://stackoverflow.com/questions/14337517/writing-struct-to-mapped-memory-file-mmap 类似,如何在Go中将结构体写入mmap文件或使用结构体更新mmap文件?
假设我的二进制文件以二进制头开始:
type MVHD struct {
Version byte
Flags [3]byte
DateCreated time.Time
DateModified time.Time
TimeUnit uint32 // 每秒的时间单位(默认为600)
DurationInUnits uint64 // 时间长度(以时间单位计算)
Raw []byte // 解码后的位上方的未解码数据
}
假设我想将其映射为内存文件并更新DateModified
字段,是否可能?
(我对Go中的mmap的有限阅读是它只能通过字节数组访问,但我确信有一种通过结构体访问它的方法。我在这里找到了一个示例,它使用了reflect
,但对我来说太复杂了,无法掌握基本思想)
英文:
Similar to https://stackoverflow.com/questions/14337517/writing-struct-to-mapped-memory-file-mmap, how to write a struct to mmap file or update mmap file with struct in Go?
Suppose my binary file begins with a binary header of
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
}
Say I want to map it as memory file and update the DateModified
field, is that possible?
(my limited reading on mmap in Go is that it can only be accessed via byte array, but I'm sure there is a way to access it via struct. I found one here using reflect
but it is too complicated for me to grasp the basic idea)
答案1
得分: 2
你可以使用encoding/binary
来读取/写入固定大小的结构体。这种方法是可移植的,不依赖于内存布局、编译器或CPU架构。例如:
// 注意:解码时使用uint32而不是time.Time。
// 如果需要,之后再转换为time.Time。
type MVHD struct {
Version byte
Flags [3]byte
DateCreatedSecs uint32
DateModifiedSecs uint32
TimeUnit uint32 // 每秒的时间单位(默认为600)
DurationInUnits uint64 // 时间长度(以时间单位计算)
}
// ..或者使用binary.BigEndian - 根据你的数据选择正确的字节序。
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
。这将允许你将mmap数据与decode
一起使用。
或者,你可以手动解码:
func decode2(buf []byte) (*MVHD, error) {
if len(buf) < 24 {
return nil, errors.New("数据不足")
}
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("数据不足")
}
binary.LittleEndian.PutUint32(buf[8:12], t)
return nil
}
英文:
You can use encoding/binary
to read/write fixed size structs. This approach is portable and doesn't depend on the memory layout, compiler, or CPU architecture. Eg:
// 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
}
Use bytes.NewReader
to convert a []byte
into an io.Reader
. This will allow you to use decode
with mmap data.
Alternatively, you can decode it manually:
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
}
Similarly, you can update data in place with binary.ByteOrder
Put
calls:
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论