2012-06-25 63 views
0

我使用GZipStream來壓縮一個字符串,我修改了兩個不同的例子來看看有什麼作用。第一個代碼片段是the example in the documentation的重大修改版本,它只是返回一個空字符串。爲什麼一個字符串壓縮方法返回一個空字符串,但另一個不是?

public static String CompressStringGzip(String uncompressed) 
{ 
    String compressedString; 
    // Convert the uncompressed source string to a stream stored in memory 
    // and create the MemoryStream that will hold the compressed string 
    using (MemoryStream inStream = new MemoryStream(Encoding.Unicode.GetBytes(uncompressed)), 
         outStream = new MemoryStream()) 
    { 
     using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress)) 
     { 
      inStream.CopyTo(compress); 
      StreamReader reader = new StreamReader(outStream); 
      compressedString = reader.ReadToEnd(); 
     } 
    } 
    return compressedString; 

,當我調試它,我能告訴什麼是從reader,這是compressedString是空讀取。但是,我寫的第二種方法,從CodeProject snippet修改成功。

public static String CompressStringGzip3(String uncompressed) 
{ 
    //Transform string to byte array 
    String compressedString; 
    byte[] uncompressedByteArray = Encoding.Unicode.GetBytes(uncompressed); 

    using (MemoryStream outStream = new MemoryStream()) 
    { 
     using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress)) 
     { 
      compress.Write(uncompressedByteArray, 0, uncompressedByteArray.Length); 
      compress.Close(); 
     } 
     byte[] compressedByteArray = outStream.ToArray(); 
     StringBuilder compressedStringBuilder = new StringBuilder(compressedByteArray.Length); 
     foreach (byte b in compressedByteArray) 
      compressedStringBuilder.Append((char)b); 
     compressedString = compressedStringBuilder.ToString(); 
    } 
    return compressedString; 
} 

爲什麼第一個代碼段不成功,而另一個是?儘管它們略有不同,但我不知道爲什麼第二個片段中的細微變化可以讓它起作用。我使用的樣本串SELECT * FROM foods f WHERE f.name = 'chicken';

+0

任何與流的位置有關?在閱讀之前,您是否嘗試過在方法1中試圖尋找流的開始? – Charleh

+0

我添加了'inStream.Seek(0L,SeekOrigin.Begin);'在行之前:'inStream.CopyTo(compress);',但該方法仍然返回一個空字符串。 –

回答

1

我結束了使用下面的代碼壓縮及解壓縮:

public static String Compress(String decompressed) 
{ 
    byte[] data = Encoding.UTF8.GetBytes(decompressed); 
    using (var input = new MemoryStream(data)) 
    using (var output = new MemoryStream()) 
    { 
     using (var gzip = new GZipStream(output, CompressionMode.Compress, true)) 
     { 
      input.CopyTo(gzip); 
     } 
     return Convert.ToBase64String(output.ToArray()); 
    } 
} 

public static String Decompress(String compressed) 
{ 
    byte[] data = Convert.FromBase64String(compressed); 
    using (MemoryStream input = new MemoryStream(data)) 
    using (GZipStream gzip = new GZipStream(input, CompressionMode.Decompress)) 
    using (MemoryStream output = new MemoryStream()) 
    { 
     gzip.CopyTo(output); 
     StringBuilder sb = new StringBuilder(); 
     return Encoding.UTF8.GetString(output.ToArray()); 

    } 
} 

的解釋問題的一部分來自this question。雖然我的代碼改變什麼,我包括在此回答解決了問題,這些線(在我的原碼):

foreach (byte b in compressedByteArray) 
      compressedStringBuilder.Append((char)b); 

是有問題的,因爲dlev貼切的話來說:

You are interpreting each byte as its own character, when in fact that is not the case. Instead, you need the line:

string decoded = Encoding.Unicode.GetString(compressedByteArray); 

The basic problem is that you are converting to a byte array based on an encoding, but then ignoring that encoding when you retrieve the bytes.

因此,問題解決了,我使用的新代碼比我原來的代碼簡潔得多。

0

你需要以下移動代碼的第二using語句外:

using (GZipStream compress = new GZipStream(outStream, CompressionMode.Compress)) 
{ 
    inStream.CopyTo(compress); 
    outStream.Position = 0; 
    StreamReader reader = new StreamReader(outStream); 
    compressedString = reader.ReadToEnd(); 
} 

CopyTo從()不沖洗,結果到底層的MemoryStream。

更新

似乎GZipStream關閉和處置,當它被設置(不是我會設計類的方式),它的底層流。我已經更新了上面的示例並對其進行了測試。

+0

第二個(內部?)'使用'語句?我得到一個錯誤,說如果我把代碼移到那裏,outStream是不可讀的。 –

+0

如何只手動使用stream.Flush()手動刷新流? – Charleh

+0

@Charleh也可以工作,但我認爲在使用語句之外執行它更具可讀性,因爲它清楚地區分了兩個任務。 – Slugart

相關問題