快速解析Java二进制格式

5

我经常在我们的Java EE应用程序套件中处理不同的二进制文件格式,即将它们读入到某些类结构中并将其写回。我需要进行以下操作:

  • read single byte / short / int / long, sometimes different endianness (little/big)
  • read single bits in flags, i.e.

    | uint16_t | 4 bits | 4 bits | uint16_t |
    

    should become something like

    a = stream.readUint16();
    byte tmp = stream.readUint8();
    b = (tmp & 0xf0) >> 4;
    c = (tmp & 0xf)
    d = stream.readUint16();
    
  • read strings in different encodings, sometimes dynamic length strings with something like a \0 ending

  • seeking in a file (to find data dictated by some offsets read), knowing current position, knowing how much have I left to parse in current data block
  • last, but not least, it should be fast; at least not an order of magnitude slower than declaring a typedef struct in C, reading it as a block and typecasting it in memory
到目前为止,我已经分析了我的选项,并发现有以下几种选择:
- `RandomAccessFile` - 在标准Java中是最好的选择,具有适当的查找和定位方法、字符串读取等功能,但由于缺乏缓冲区,在像...这样的操作中有时会无法忍受的慢;此外,没有对流进行位级访问和不同字节序支持。 - `FileInputStream` - 只能读取单个字节,需要手动重构原始数据类型;没有查找功能。 - `*Reader` 接口 - 基本上只能读取字节和字节数组,可以跳过、标记和重置,但如果多次执行查找,则容易泄漏内存,如 `reset(); skip(seekAmount);`。 - https://github.com/raydac/java-binary-block-parser - 几乎完全符合我的要求 - 即格式的声明性规范,然后就有了类,但它本质上是一个解释器,因此存在两个主要问题:(a)在高需求环境下速度较慢,(b)存在多个类型安全问题,类似于运行时生成的反射。 - http://preon.codehaus.org/ - 有很多好评,但似乎已不再开发,网站已关闭 :(
我在Google和StackOverflow上搜索了一下。这个问题 - How to parse/encode binary message formats? - 解决了相同的问题,但有奇怪的非对齐位要求,而我没有这个要求。
所以,问题是 - 我是否忽略了什么,有没有更好的解决方案来解决我提到的所有问题?

1
Preon仍然健康而且活跃,只是不在Codehaus了。但是,我认为这对你没有太大帮助,因为你并没有处理未对齐的结构体。 - GreyCat
2个回答

7

ByteBuffer提供了你所需的一切。
在纯Java中,它很可能是最快的选择(不包括JNI、sun.misc.Unsafe等)。


0

我不太想建议这个作为解决方案,但是考虑到你似乎有一些在C语言中如何实现的知识,你可以构建一个适当的C函数库,然后用JNI进行封装,在你的应用程序中使用它。

也许这只是那些罕见情况之一,对于你的用例来说“走本地化”是合适的?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接