用scala解析二进制数据

nur*_*ion 13 scala

我需要解析一些简单的二进制文件.(这些文件包含n个条目,其中包含几个不同大小的有符号/无符号整数等)

在那一刻,我"手工"解析.有人知道有助于进行此类解析的库吗?

编辑:"手动"意味着我通过字节获取数据字节将其排序为正确的顺序并将其转换为Int/Byte等.还有一些数据是无符号的.

Aar*_*ron 7

我之前使用过sbinary库,非常好.文档有点稀疏,但我建议先查看旧维基页面,因为它为您提供了一个起点.然后查看测试规范,因为它给你一些非常好的例子.

sbinary的主要好处是它为您提供了一种方法来将每个对象的有线格式描述为Format对象.然后,您可以将这些格式化的类型封装在更高级别的Format对象中,只要您将它作为隐式对象包含在当前作用域中,Scala就可以完成查找该类型的所有繁重工作.

正如我在下面所说,我现在建议人们使用scodec而不是sbinary.作为如何使用scodec的示例,我将实现如何在以下C结构的内存中读取二进制表示:

struct ST
{
   long long ll; // @ 0
   int i;        // @ 8
   short s;      // @ 12
   char ch1;     // @ 14
   char ch2;     // @ 15
} ST;
Run Code Online (Sandbox Code Playgroud)

匹配的Scala案例类将是:

case class ST(ll: Long, i: Int, s: Short, ch1: String, ch2: String)
Run Code Online (Sandbox Code Playgroud)

我只是说我们存储了Strings而不是Chars,这让我自己变得更容易了,我会说它们在结构中是UTF-8字符.我也没有处理endian细节或者这个架构上long和int类型的实际大小,只是假设它们分别是64和32.

Scodec解析器通常使用组合器从较低级别的解析器构建更高级别的解析器.因此,对于下面,我们将定义一个解析器,它结合了一个8字节值,一个4字节值,一个2字节值,一个1字节值和一个1字节值.这个组合的返回是一个元组编解码器:

val myCodec: Codec[Long ~ Int ~ Short ~ String ~ String] = 
  int64 ~ int32 ~ short16 ~ fixedSizeBits(8L, utf8) ~ fixedSizeBits(8L, utf8)
Run Code Online (Sandbox Code Playgroud)

然后我们可以通过调用xmap它上面的函数将它转换为ST case类,它接受两个函数,一个用于将Tuple编解码器转换为目标类型,另一个函数用于获取目标类型并将其转换为Tuple形式:

val stCodec: Codec[ST] = myCodec.xmap[ST]({case ll ~ i ~ s ~ ch1 ~ ch2 => ST(ll, i, s, ch1, ch2)}, st => st.ll ~ st.i ~ st.s ~ st.ch1 ~ st.ch2)
Run Code Online (Sandbox Code Playgroud)

现在,您可以像这样使用编解码器:

stCodec.encode(ST(1L, 2, 3.shortValue, "H", "I"))
res0: scodec.Attempt[scodec.bits.BitVector] = Successful(BitVector(128 bits, 0x00000000000000010000000200034849))

res0.flatMap(stCodec.decode)
=> res1: scodec.Attempt[scodec.DecodeResult[ST]] = Successful(DecodeResult(ST(1,2,3,H,I),BitVector(empty)))
Run Code Online (Sandbox Code Playgroud)

我鼓励你看Scaladocs而不是指南,因为Scaladocs中有更多的细节.该指南在基础知识方面是一个良好的开端,但它并没有进入组成部分,但Scaladocs很好地覆盖了它.


Rex*_*err 5

Scala 本身没有二进制数据输入库,但该java.nio包做得不错。它没有显式处理无符号数据——Java 也没有,所以您需要弄清楚如何管理它——但它确实有考虑字节顺序的方便的“get”方法。