让我试着解释一下Preon是如何解决你提到的所有问题的:
“我需要在Java中解析(转换和写入)一个大型二进制文件(比内存还大)。”
这正是Preon被创建的原因。您希望能够处理整个文件,而不需要将其全部加载到内存中。尽管如此,程序模型会给您一个指向数据结构的指针,该数据结构看起来完全在内存中。但是,Preon会尽可能地懒惰地加载数据。
为了说明这意味着什么,想象一下,在您的数据结构中的某个地方,您有一个使用恒定大小进行二进制表示的事物集合;假设每个元素都将以20个字节编码。然后,Preon首先根本不会在内存中加载该集合,如果您获取超出该集合的数据,它将根本不会触及您的编码表示的那个区域。但是,如果您选择该集合的第300个元素,它将(而不是解码所有元素直到第300个元素),计算该元素的偏移量,并立即跳转到那里。
从外部看,好像你有一个完全填充的列表的引用。从内部来看,只有在你要求它时才会去获取列表的元素。(除非你指示Preon以不同的方式处理)。
“我也需要在单个线程中尽可能高效地完成操作。”我不确定你所说的“高效”是什么意思。它可能是指在内存消耗方面高效,或者在磁盘IO方面高效,或者你可能是指它应该非常快。我认为可以说Preon旨在在易于编程模型、内存使用和其他一些问题之间取得平衡。如果你真的需要以顺序方式遍历所有数据,那么也许有更有效的计算资源方面的方法,但我认为这将以“易于编程”的代价为代价。
最后,被读取的格式非常结构化,因此最好有某种解析器库(这样代码就接近复杂的规范)。
我实现对Java字节码的支持方式是仅仅阅读字节码规范,然后将其中提到的所有结构直接映射到带有注释的Java类中。我认为Preon非常接近你所寻找的内容。
你可能还想查看preon-emitter,因为它允许您生成带注释的十六进制转储(例如在
此Java类文件的十六进制转储示例中),这是我在任何其他库中都没有看到的功能。(提示:确保您将鼠标悬停在十六进制数字上。)
对于它生成的文档也是如此。目标一直是确保它创建的文档可以像那样发布到维基百科。虽然它可能还不完美,但我对它目前能够做到的感到满意。(例如:
这是Java类文件规范生成的文档示例。)
引用:“解析所需的前瞻量应该很小,如果这很重要。”
好的,很好。实际上,这对Preon来说甚至是至关重要的。Preon不支持前瞻。但它确实支持回溯。(也就是说,有时候编码机制的一部分是由之前读取的数据驱动的。Preon允许您声明指向之前读取数据的依赖关系。)
有没有适用于二进制数据的好的解析器库?
Preon! ;-)
解析器对流转换的支持如何(我想能够在解析过程中将正在解析的数据流传输到某些输出 - 我不想在编写输出之前构建整个解析树)?
正如我上面所概述的,Preon在您开始处理它之前并不会将整个数据结构构建在内存中。所以,在这个意义上,你是好的。然而,Preon中没有任何支持转换作为一等公民的东西,它对编码的支持也是有限的。
在nio方面,我怀疑nio不会有太大的帮助,因为我很可能受到磁盘限制(而且由于是单线程,只需简单地阻塞即可)。此外,我认为基于io的解析器更为常见。
Preon使用NIO,但仅限于内存映射文件的支持。