我很清楚encoding/binary
不能处理可变类型(比如string)。我的问题如下:
我有一些用pascal语言编写的程序生成的旧二进制文件。如果没有字符串类型,我本来可以很容易地阅读它。Pascal允许你声明一个最大长度的字符串(长度不能超过255个字符),但它会将其保存到一个字节数较少的文件中以节省磁盘空间。例如,如果我有以下声明:
var a_string: string[200];
a_string := "AAAA"
那么文件将以以下字节结束:
0x04 0x41 0x41 0x41 0x41
^^^^ ^^^^^^^^^^^^^^^^^^^
| +---------- content
+---------------------- length
到目前为止一切都很好,没有什么特别有争议的。我的问题是,我试图把它挂到binary.read上,它显然失败了,因为binary.read只能解析固定大小的结构。然而,我的问题是,阅读这个结构的唯一方法是以下方式:
https://go.dev/play/p/OZRgaDqh9cc
当然可以,但是看起来很丑。假设结构体中有13个字段,其中只有3个字段是pascal字符串类型。我是不是漏掉了什么?换句话说,是否有一些使用的读者界面,我无法谷歌出来?基本上,我在这里要做的唯一一件事就是为这个自定义类型覆盖bytes.Reader的行为。
有两种方法,我可以想到,来到我的脑海。首先是通过反射遍历结构体,并相应地对恰好是pascal字符串类型的字段做出React。但这似乎是一个巨大的过度杀戮。
第二种方法:
1/将我可以读取的“纯”类型与常规binary.Read
一起 Package 在子结构中
2/使用totalBytesRead, _ = reader.Seek(0, os.SEEK_CUR)
获取缓冲区内的“当前”位置
3/使用自定义的.Read()
(将返回bytesRead
)读取pascal字符串,并将totalBytesRead
递增bytesRead
4/使用reader.Seek(totalBytesRead, os.SEEK_SET)
并继续使用binary.Read
但似乎还是...我的直觉告诉我这样做不对
我也尝试过:
- 创建一个如下类型别名,希望诱使encoding/binary认为它只需要分配一个更大的缓冲区:
type PString [255]byte
- 看看二进制协议的现有实现。所以我看了一下这个代码:https://github.com/elcapitansam/gostruct/tree/master,但这是一个稍微不同的问题,因为它解码成“纯”接口。我的问题略有不同,因为我已经知道我想要解析的目标接口是什么。
1条答案
按热度按时间fhg3lkii1#
我尝试了反射方法,以下是我能够实现的解决方案:
https://go.dev/play/p/MPBOmQAmECl
(it使用编解码器的动态Map,而不是在函数中硬编码所有内容)
对我来说还是太复杂了。我的意思是,我一直认为,如果其他方法都失败了,使用反射将是解决方案,但我的问题似乎太简单了,以至于这个解决方案似乎是错误的,至少直观上是错误的。另外,在这种方法中,仍然需要为所有int / uint和float类型实现解码器函数