我需要在字节缓冲区中提取各种字段。我提出了这个解决方案:
func (fs *FileSystem) readSB() {
// fs.f is a *os.File
buf := make([]byte, 1024)
fs.f.ReadAt(buf, 1024)
// Offset: type
var p *bytes.Buffer
// 0: uint32
p = bytes.NewBuffer(buf[0:])
binary.Read(p, binary.LittleEndian, &fs.sb.inodeCount)
// 4: uint32
p = bytes.NewBuffer(buf[4:])
binary.Read(p, binary.LittleEndian, &fs.sb.blockCount)
// 20: uint32
p = bytes.NewBuffer(buf[20:])
binary.Read(p, binary.LittleEndian, &fs.sb.firstDataBlock)
// 24: uint32
p = bytes.NewBuffer(buf[24:])
binary.Read(p, binary.LittleEndian, &fs.sb.blockSize)
fs.sb.blockSize = 1024 << fs.sb.blockSize
// 32: uint32
p = bytes.NewBuffer(buf[32:])
binary.Read(p, binary.LittleEndian, &fs.sb.blockPerGroup)
// 40: uint32
p = bytes.NewBuffer(buf[40:])
binary.Read(p, binary.LittleEndian, &fs.sb.inodePerBlock)
}
是否有更好/惯用/直接的方法?
答案 0 :(得分:30)
每次使用.Next()
跳过您不想读取的字节,可以避免每次都创建一个新的缓冲区:
{
// Offset: type
p := bytes.NewBuffer(buf)
// 0: uint32
binary.Read(p, binary.LittleEndian, &fs.sb.inodeCount)
// 4: uint32
binary.Read(p, binary.LittleEndian, &fs.sb.blockCount)
// Skip [8:20)
p.Next(12)
// 20: uint32
binary.Read(p, binary.LittleEndian, &fs.sb.firstDataBlock)
// 24: uint32
binary.Read(p, binary.LittleEndian, &fs.sb.blockSize)
fs.sb.blockSize = 1024 << fs.sb.blockSize
// Skip [28:32)
p.Next(4)
// 32: uint32
binary.Read(p, binary.LittleEndian, &fs.sb.blockPerGroup)
// Skip [36:40)
p.Next(4)
// 40: uint32
binary.Read(p, binary.LittleEndian, &fs.sb.inodePerBlock)
}
或者您可以避免按块读取块并创建一个使用binary.Read
直接读取的头结构:
type Head struct {
InodeCount uint32 // 0:4
BlockCount uint32 // 4:8
Unknown1 uint32 // 8:12
Unknown2 uint32 // 12:16
Unknown3 uint32 // 16:20
FirstBlock uint32 // 20:24
BlockSize uint32 // 24:28
Unknown4 uint32 // 28:32
BlocksPerGroup uint32 // 32:36
Unknown5 uint32 // 36:40
InodesPerBlock uint32 // 40:44
}
func main() {
var header Head
err = binary.Read(file, binary.LittleEndian, &header)
if err != nil {
log.Fatal(err)
}
log.Printf("%#v\n", header)
}
答案 1 :(得分:1)
我有一个包binpacker来处理这些情况
示例数据:
buffer := new(bytes.Buffer)
packer := binpacker.NewPacker(buffer)
unpacker := binpacker.NewUnpacker(buffer)
packer.PushByte(0x01)
packer.PushUint16(math.MaxUint16)
打开包装:
var val1 byte
var val2 uint16
var err error
val1, err = unpacker.ShiftByte()
val2, err = unpacker.ShiftUint16()
或者
var val1 byte
var val2 uint16
var err error
unpacker.FetchByte(&val1).FetchUint16(&val2)
unpacker.Error() // Make sure error is nil