我有一个文本文件,其中包含IPv6范围以及范围所属的ISP(范围不重叠)。一些样本(假)行如下:
2010:258:0:0:0:0:0:0;2010:258:ffff:ffff:ffff:ffff:ffff:ffff;ISP_1;
2010:260:0:0:0:0:0:0;2010:260:ffff:ffff:ffff:ffff:ffff:ffff;ISP_2;
2010:268:0:0:0:0:0:0;2010:268:ffff:ffff:ffff:ffff:ffff:ffff;ISP_3;
我已经使用了这个文本文件并创建了一个Interval Tree,这样我就可以快速查找特定IP所属的ISP。 Interval树中的每个节点都具有以下结构:
public class Node implements Serializable {
Range nodeRange;
IntervalTreeNode left;
IntervalTreeNode right;
UnsignedLong128 centerValue;
}
以下是Range
:
public abstract class Range implements Comparable<Range>, Serializable {
UnsignedLong128 start;
UnsignedLong128 end;
boolean sortAccordingToStart;
}
其中UnsignedLong128
是我写的自定义Long类,长度为128位:
public class UnsignedLong128 implements Comparable<UnsignedLong128>, Serializable {
Long major;
Long minor;
}
问题是,如果我将树序列化并将树写入文件,该文件的大小比原始文本文件大。这是一个例子:我有一个包含19860范围行的文本文件,该文本文件的大小为1.7 MB。当我基于它创建Interval Tree并将该树写入文件(通过Java的序列化)时,生成的文件的大小为15.7 MB ,即使它存储相同的信息。是的,树的节点数量是文本文件中行数的两倍(我正在生成的树是平衡的),这仍然不能证明文件大小增加太多。
那么导致这个文件大小增长的原因是什么?我怎样才能减少它?
答案 0 :(得分:1)
Java序列化会产生很多开销,如果你用文本编辑器查看文件,你可能会看到它。
由于范围不重叠,您可以将数据保持在排序顺序(比较两个范围,比较它们的起点或终点),并使用二进制搜索来查找匹配项。然后你只需序列化一组结构。您可能会发现Java序列化的开销较小,您有一个大型阵列或三个大型阵列,包含起点,终点和ISP ID,或者您可以自己读取和写入数据。
您还可以调查readResolve()和writeReplace()
答案 1 :(得分:0)
您可以实现Externalizable
,它允许您在保持Serializable
框架的同时自定义序列化。它相当简单,你需要每场和每个方向一行。 Serializable
有一些开销,因为每个字段可能包含null
或其类型的子类的实例,但您通常知道它不会发生。
我不确定,但我想Serializable
默认使用UTF-16,这是快速而简单的,就像Java内部所做的那样(或者像Java 9那样做)可以做得更好),但它为你的纯ASCII浪费了两倍(使用UTF-8很好)。看起来你用数字替换了字符串,所以它可能没什么帮助。
你的UnsignedLong128
在记忆中也很浪费。将Long
替换为long
。不知道,它对序列化数据大小有多大帮助,但是你节省了大量的RAM(并获得了一些速度)。