【发布时间】:2017-07-28 09:42:58
【问题描述】:
对于一个项目,我经常处理大量使用大量读取的加密数据。由于解密比膨胀需要更长的时间,我愿意在加密和存储之前对数据进行放气。
我面临的困难是数据存储在固定长度的块或页面中。磁盘上的这些块需要保持固定长度才能进行快速页面查找。所以基本上我试图将尽可能多的数据压缩到一个固定大小的页面中。
目前我正在尝试找到一个好的方法来做到这一点。但是,此时我有点卡在每次添加数据时跟踪压缩大小并且未压缩大小接近页面限制。 (因为如果数据的熵非常高,理论上数据也会由于压缩而增长一点)。目前,我正在尝试以下方法:
final Deflater deflater = new Deflater();//Deflater.HUFFMAN_ONLY);
final Inflater inflater = new Inflater();
long start;
long duration;
int freeSpace = size;
int fill = 0;
byte[] page;
final byte[] buf = new byte[8];
deflater.reset();
try( ByteArrayOutputStream boas = new ByteArrayOutputStream(size);
DeflaterOutputStream dos = new DeflaterOutputStream(boas, deflater, size, true)){
start = System.currentTimeMillis();
while(true){
long compressable = (long) (Random.nextLong(30) + 100);
fill += ByteTools.longToByteArray(compressable, buf, 0, 8);
dos.write(buf);
freeSpace = size - boas.size();
if(freeSpace < 16){
System.out.println(boas.size());
dos.finish();
System.out.println(boas.size());
page = boas.toByteArray();
break;
}
}
duration = System.currentTimeMillis() - start;
}
上面的代码可以用于放气,但是输出的长度在 dos.finished() 上显着增加。这并不奇怪,但是有没有什么好的方法来确定最终的输出大小,或者还有其他更适合该任务的压缩方案吗?
由于可以应用填充,因此不需要 100% 准确的输出大小,因此 95%-100% 的范围将是完美且足够高性能的。当然,应始终防止 100%+。
基于跟踪和错误,我稍微调整了例程,这给了我很好的结果。但是我对这个解决方案还不是很满意。
while(true){
long compressable = (long) (Random.nextLong(30) + 100);
block += ByteTools.longToByteArray(compressable, buf, 0, 8);
dos.write(buf);
if(block >= check){
//check /= 2;
dos.flush();
fill += block;
block = 0;
check = (size - boas.size()) - 8;
System.out.println(check);
}
if(check < 16){
fill += block;
dos.finish();
page = boas.toByteArray();
break;
}
}
该解决方案的压缩比与原始压缩比(在一个块中)相差不远,并且保持在所需输出大小的 8 字节以内。支票大小的减少有以下几种形式:
16384
8088
4259
2207
1110
540
246
94
32
3
在页面生成期间导致 9 次刷新和 1 次完成。
【问题讨论】: