2009-10-06 185 views
4

我在使用C#.NET讀取壓縮的(放縮的)數據文件時遇到問題DeflateStream(..., CompressionMode.Decompress)。該文件早先使用DeflateStream(..., CompressionMode.Compress)編寫,似乎很好(我甚至可以使用Java程序對其進行解壓縮)。使用DeflateStream解壓縮數據文件

但是,調用輸入流的第一個Read()來解壓縮/擴展壓縮數據返回長度爲零(文件結束)。

這裏的主要驅動力,這是用於壓縮和解壓的:

public void Main(...) 
{ 
    Stream inp; 
    Stream outp; 
    bool compr; 

    ... 
    inp = new FileStream(inName, FileMode.Open, FileAccess.Read); 
    outp = new FileStream(outName, FileMode.Create, FileAccess.Write); 

    if (compr) 
     Compress(inp, outp); 
    else 
     Decompress(inp, outp); 

    inp.Close(); 
    outp.Close(); 
} 

下面是減壓的基本代碼,這就是失敗:

public long Decompress(Stream inp, Stream outp) 
{ 
    byte[] buf = new byte[BUF_SIZE]; 
    long nBytes = 0; 

    // Decompress the contents of the input file 
    inp = new DeflateStream(inp, CompressionMode.Decompress); 

    for (;;) 
    { 
     int len; 

     // Read a data block from the input stream 
     len = inp.Read(buf, 0, buf.Length); //<<FAILS 
     if (len <= 0) 
      break; 

     // Write the data block to the decompressed output stream 
     outp.Write(buf, 0, len); 
     nBytes += len; 
    } 

    // Done 
    outp.Flush(); 
    return nBytes; 
} 

呼叫標記FAILS總是返回零。爲什麼?我知道這很簡單,但我只是沒有看到它。

下面是壓縮的基本代碼,它工作得很好,並幾乎完全一樣,名稱分別減壓方法交換:

public long Compress(Stream inp, Stream outp) 
{ 
    byte[] buf = new byte[BUF_SIZE]; 
    long nBytes = 0; 

    // Compress the contents of the input file 
    outp = new DeflateStream(outp, CompressionMode.Compress); 

    for (;;) 
    { 
     int len; 

     // Read a data block from the input stream 
     len = inp.Read(buf, 0, buf.Length); 
     if (len <= 0) 
      break; 

     // Write the data block to the compressed output stream 
     outp.Write(buf, 0, len); 
     nBytes += len; 
    } 

    // Done 
    outp.Flush(); 
    return nBytes; 
} 

解決

看到正確的解決方案後, ,構造語句應更改爲:

inp = new DeflateStream(inp, CompressionMode.Decompress, true); 

它將底層輸入流開放,以下線路需要添加以下的inp.Flush()電話:

inp.Close(); 

Close()調用強制deflater流刷新其內部緩衝區。 true標誌阻止它關閉底層流,後面在Main()後關閉。還應該對Compress()方法進行相同的更改。

回答

4

在您的解壓縮方法中,將inp重新分配給新的Stream(縮放流)。你永遠不關閉這個Deflate流,但是你關閉了Main()中的底層文件流。壓縮方法正在進行類似的事情。

我認爲問題是在緊縮流的終結器自動關閉它們之前,底層文件流正在關閉。

我加1行代碼的解壓縮和壓縮的方法: inp.Close()//到Decompressmehtod

outp.Close()//到壓縮方法。

更好的做法是將這些流封裝在using子句中。

這裏是寫你的解壓方法(我測試,和它的作品)

 

    public static long Decompress(Stream inp, Stream outp) 
    { 
     byte[] buf = new byte[BUF_SIZE]; 
     long nBytes = 0; 

     // Decompress the contents of the input file 
     using (inp = new DeflateStream(inp, CompressionMode.Decompress)) 
     { 
      int len; 
      while ((len = inp.Read(buf, 0, buf.Length)) > 0) 
      { 
       // Write the data block to the decompressed output stream 
       outp.Write(buf, 0, len); 
       nBytes += len; 
      } 
     } 
     // Done 
     return nBytes; 
    } 
 
+0

@LoadMaster另一種方法:BTW:當我跑了你的代碼,我沒有得到你所描述的相同的行爲,但它也沒有工作。在我的情況下,解壓縮似乎是成功的,但如果我將解壓縮的文件與原始文件進行比較,它們不匹配。解壓縮的文件比原來的缺少的字節小。 我們在DeflateStream上調用close()的更改也修復了這個問題。我懷疑行爲上的差異可能與我的測試文件的大小有關 - 也許它會丟失最後的N個字節,並且我的文件比較大(我的文件是364,391字節)。 – JMarsch 2009-10-07 15:55:14

+0

Doh。當然,它在文檔中說有必要關閉deflater流以確保所有內部緩衝區都被正確刷新。我應該在Decompress()和Compress()方法中調用壓縮器/解壓縮器流上的'Close()',因爲它們直接控制壓縮器/解壓縮器流。 或者,我可以用'keepOpen'標誌打開'DeflaterStream'來保持底層輸入流的打開狀態。我仍然關閉deflater流,但之後我還要關閉底層文件流。我嘗試了這一點,它的工作原理。 – 2009-10-07 17:00:52

0

我有與GZipStream相同的問題,因爲我們有原始長度存儲,我不得不重新編寫代碼,只讀取原始文件中預期的字節數。

希望我即將知道有一個更好的答案(手指交叉)。