0

私はGZipStream文字列を圧縮するために使用しています.2つの異なる例を変更して、何が機能するかを確認しました. ドキュメントの例を大幅に変更した最初のコード スニペットは、単に空の文字列を返します。

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 スニペットから変更した、私が書いた 2 番目のメソッドは成功しています。

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;
}

最初のコード スニペットは成功しないのに、もう 1 つのコード スニペットは成功するのはなぜですか? 多少の違いはありますが、2 番目のスニペットのマイナーな変更によって機能する理由がわかりません。私が使用しているサンプル文字列はSELECT * FROM foods f WHERE f.name = 'chicken';

4

2 に答える 2

2

圧縮と解凍に次のコードを使用することになりました。

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());

    }
}

問題の一部の説明は、この質問から来ています。コードをこの回答に含めたものに変更することで問題を修正しましたが、これらの行 (元のコード):

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

dlevが適切に表現したように、問題があります。

実際にはそうではない場合、各バイトを独自の文字として解釈しています。代わりに、次の行が必要です。

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

基本的な問題は、エンコーディングに基づいてバイト配列に変換しているが、バイトを取得するときにそのエンコーディングを無視することです。

したがって、問題は解決され、使用している新しいコードは元のコードよりもはるかに簡潔になります。

于 2012-06-25T19:27:43.993 に答える
0

以下のコードを 2 番目の 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 は、破棄されたときに基になるストリームを閉じて破棄するようです (クラスを設計した方法ではありません)。上記のサンプルを更新してテストしました。

于 2012-06-25T15:43:31.897 に答える