对于一个项目,我使用大量加密数据工作很多,这些数据用得很重。由于解密比充气要长得多,我愿意在加密和存储之前对数据进行收缩。
我面临的困难是数据存储在固定长度的块或页面中。磁盘上的这些块需要保持固定长度,以便快速查找页面。所以基本上我试图将尽可能多的数据放入固定大小的页面。
目前我正试图找到一个好方法。但是,此时每次添加数据并且未压缩的大小接近页面限制时,我都会陷入压缩大小。 (因为如果数据的熵非常高,理论上数据在理论上也会因压缩而增长一点)。目前,我正在尝试以下方法:
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
在页面生成和完成1次期间导致9次刷新。
答案 0 :(得分:1)
想法是压缩超过块大小,仅解压缩块大小,然后仅重新压缩解压缩的内容。你这样做了两次,以便非常接近,或者很多时候,完全填满了这块。