對於一個項目,我使用大量的加密數據來處理大量的讀取數據。由於解密需要比膨脹更長的時間,所以我願意在加密和存儲之前壓縮數據。將數據放入一個固定長度的緩衝區中
我面臨的困難是數據存儲在固定長度的塊或頁面中。磁盤上的這些塊需要保持固定長度以便快速查找頁面。所以基本上我試圖儘可能多地將數據泄漏到固定大小的頁面中。
在目前我試圖找到一個很好的方法來做到這一點。然而,在這一刻,我有點卡住每次添加數據後壓縮的大小和未壓縮的大小接近頁面限制。 (因爲如果數據的熵很高,數據在理論上可能由於壓縮而增長一點)。目前,我試圖以下方法:
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;
}
}
的解決方案具有的壓縮率是不遠處的原始comression比率(在一個塊)和8個字節所需的輸出尺寸的內停留。檢查大小減少採取以下形式:
16384
8088
4259
2207
1110
540
246
94
32
3
導致在頁面生成和1完成9刷新。
這仍然需要一些關於壓縮率的猜測,以便知道什麼會壓縮到填充塊大小以上。但它給了我一個非常好的提示,即使用部分解壓縮。在我的場景中,我可以在「未分頁」文件的「尾部」使用緩衝區,並在緩衝區超過頁面大小時對其進行分頁。我會寫更多的測試,看看它是否適合這種情況。謝謝。 –
不需要猜測。對於第一遍,只是繼續壓縮,直到你過滿了塊。 –
在使用Comressor及其OutputStream的Java中時,輸出大小在刷新之前不會更新。據我瞭解,沖洗導致壓縮循環,所以爲了防止調用沖洗太頻繁,我需要估計。 –