Java:将大量数据序列化为单个文件

时间:2020-03-06 14:41:15  来源:igfitidea点击:

我需要将小对象的大量数据(大约2gigs)序列化为单个文件,以便稍后由另一个Java进程进行处理。性能是很重要的。谁能建议一个好的方法来实现这一目标?

解决方案

我们是否看过Google的协议缓冲区?听起来像是一个用例。

我们是否尝试过Java序列化?我们可以使用ObjectOutputStream将其写出,然后使用ObjectInputStream读回。当然,这些类必须是"可序列化的"。这将是省力的解决方案,并且因为对象存储在二进制文件中,所以它将紧凑且快速。

我们可能应该考虑一个数据库解决方案-所有数据库都在优化它们的信息,如果我们使用Hibernate,则可以保持对象模型不变,甚至不必考虑数据库(我相信这就是为什么它被称为hibernate的原因保存数据,然后将其恢复)

我立即想到的最简单的方法是使用NIO的内存映射缓冲区(java.nio.MappedByteBuffer)。使用一个缓冲区(大约)对应于一个对象的大小,并在必要时将其刷新/追加到输出文件中。内存映射的缓冲区非常有效。

协议缓冲区:很有意义。以下是他们的维基摘录:http://code.google.com/apis/protocolbuffers/docs/javatutorial.html

加快速度

默认情况下,协议缓冲区编译器会尝试使用反射来实现大多数功能(例如解析和序列化)来生成较小的文件。但是,编译器还可以生成针对消息类型进行了显式优化的代码,通常可以将性能提高一个数量级,但也可以使代码大小增加一倍。如果分析显示应用程序在协议缓冲区库中花费大量时间,则应尝试更改优化模式。只需将以下行添加到.proto文件中:

选项optimize_for = SPEED;

重新运行协议编译器,它将生成非常快速的解析,序列化和其他代码。

如果性能非常重要,那么我们需要自己编写。我们应该使用紧凑的二进制格式。因为使用2 GB磁盘I / O操作非常重要。如果使用XML或者其他脚本等任何人类可读格式,则将数据大小调整为2或者更大。

如果我们以低压缩率即时压缩数据,则可以根据数据来加快速度。

Java序列化是完全不可能的,因为在读取Java时,请检查每个对象是否引用了现有对象。

我不知道为什么Java序列化遭到否决,这是一种完全可行的机制。

从原始帖子尚不清楚,但是堆中的所有2G数据是否同时存在?还是我们要丢其他东西?

开箱即用,序列化不是"完美"的解决方案,但是如果我们在对象上实现Externalizable,则序列化就可以很好地工作。序列化的一大费用是弄清楚该写些什么以及如何写它。通过实施Externalizable,我们可以将这些决定从其手中掌握,从而大大提高性能并节省空间。

虽然I / O是写入大量数据的主要成本,但转换数据的附带成本也可能非常昂贵。例如,我们不想将所有数字都转换为文本,然后再转换回去,因此,如果可能的话,最好以更原始的格式存储它们。 ObjectStream具有读取/写入Java本机类型的方法。

如果将所有数据设计为加载到单个结构中,则在实现Externalizable之后,我们可以简单地执行ObjectOutputStream.writeObject(yourBigDatastructure)。

但是,我们也可以遍历结构,并在各个对象上调用writeObject。

无论哪种方式,我们都将需要一些" objectToFile"例程,也许有几个。这实际上是Externalizable提供的内容,也是构架结构的框架。

当然,另一个问题是版本控制等。但是,由于我们自己实现了所有序列化例程,因此我们也可以完全控制它。

我开发了JOAFIP作为数据库替代方案。