Распаковка GZIP-потока

Я пытаюсь распаковать строку GZipped, которая является частью ответа веб-сервиса. Строка, которая у меня есть:

"[31,-117,8,0,0,0,0,0,0,0,109,-114,65,11,-62,48,12,-123,-1,75,-50,-61,-42,-127,30,122,21,111,-126,94,60,-119,-108,-72,102,44,-48,-75,-93,-21,100,56,-6,-33,-19,20,20,101,57,37,95,-14,94,-34,4,-63,-5,-72,-73,-44,-110,-117,-96,38,-88,26,-74,38,-112,3,117,-7,25,-82,5,24,-116,56,-97,-44,108,-23,28,24,-44,-85,83,34,-41,97,-88,24,-99,23,36,124,-120,94,99,-120,15,-42,-91,-108,91,45,-11,70,119,60,-110,21,-20,12,-115,-94,111,-80,-93,89,-41,-65,-127,-82,76,41,51,-19,52,90,-5,69,-85,76,-96,-128,64,22,35,-33,-23,-124,-79,-55,-1,-2,-10,-87,0,55,-76,55,10,-57,122,-9,73,42,-45,98,-44,5,-77,101,-3,58,-91,39,38,51,-15,121,21,1,0,0]"

Я пытаюсь распаковать эту строку, используя следующий метод:

public static string UnZip(string value)
        {
            // Removing brackets from string
            value = value.TrimStart('[');
            value = value.TrimEnd(']');

            //Transform string into byte[]
            string[] strArray = value.Split(',');
            byte[] byteArray = new byte[strArray.Length];
            for (int i = 0; i < strArray.Length; i++)
            {
                if (strArray[i][0] != '-')
                    byteArray[i] = Convert.ToByte(strArray[i]);
                else
                {
                    int val = Convert.ToInt16(strArray[i]);
                    byteArray[i] = (byte)(val + 256);
                }
            }

            //Prepare for decompress
            System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray);
            System.IO.Compression.GZipStream sr = new System.IO.Compression.GZipStream(ms,
                System.IO.Compression.CompressionMode.Decompress);

            //Reset variable to collect uncompressed result
            byteArray = new byte[byteArray.Length];

            //Decompress
            int rByte = sr.Read(byteArray, 0, byteArray.Length);

            //Transform byte[] unzip data to string
            System.Text.StringBuilder sB = new System.Text.StringBuilder(rByte);
            //Read the number of bytes GZipStream red and do not a for each bytes in
            //resultByteArray;
            for (int i = 0; i < rByte; i++)
            {
                sB.Append((char)byteArray[i]);
            }
            sr.Close();
            ms.Close();
            sr.Dispose();
            ms.Dispose();
            return sB.ToString();
        }

Этот метод представляет собой модифицированную версию метода по следующей ссылке: http://www.codeproject.com/Articles/27203/GZipStream-Compress-Decompress-a-string/

К сожалению, результатом этого метода является поврежденная строка. В частности, я знаю, что входная строка содержит сжатый объект JSON, а выходная строка содержит только часть ожидаемой строки:

"{\"rootElement\":{\"children\":[{\"children\":[],\"data\":{\"fileUri\":\"file:////Luciano/e/orto_artzi_2006_0_5_pixel/index/shapefiles/index_cd20/shp_all/index_cd2.shp\",\"relativePath\":\"/i"

Любая идея, в чем может быть проблема и как ее решить?


person Zachi Shtain    schedule 01.03.2016    source источник
comment
Несжатый результат, вероятно, будет больше, чем сжатые данные. new byte[byteArray.Length] будет работать только при сжатии 1:1.   -  person Luaan    schedule 01.03.2016


Ответы (2)


Пытаться

public static string UnZip(string value)
{
    // Removing brackets from string
    value = value.TrimStart('[');
    value = value.TrimEnd(']');

    //Transform string into byte[]
    string[] strArray = value.Split(',');
    byte[] byteArray = new byte[strArray.Length];
    for (int i = 0; i < strArray.Length; i++)
    {
        byteArray[i] = unchecked((byte)Convert.ToSByte(strArray[i]));
    }

    //Prepare for decompress
    using (System.IO.MemoryStream output = new System.IO.MemoryStream())
    {
        using (System.IO.MemoryStream ms = new System.IO.MemoryStream(byteArray))
        using (System.IO.Compression.GZipStream sr = new System.IO.Compression.GZipStream(ms, System.IO.Compression.CompressionMode.Decompress))
        {
            sr.CopyTo(output);
        }

        string str = Encoding.UTF8.GetString(output.GetBuffer(), 0, (int)output.Length);
        return str;
    }
}

MemoryBuffer() не "дублирует" byteArray, но напрямую поддерживается им, поэтому вы не можете повторно использовать byteArray.

Я добавлю, что мне смешно, что они «сжали» json из 277 символов в строковый массив байтов из 620 символов.

В качестве побочного примечания, использование памяти этим методом выходит за рамки... Строка из 620 символов (которая на самом деле является 277-байтовым массивом), подлежащая распаковке, вызывает создание строк/массивов для общего размера 4887 байт (включая 620 начальных символов) (отказ от ответственности: сборщик мусора может освободить часть этой памяти во время выполнения метода). Это нормально для байтовых массивов в 277 байт... Но для больших объем памяти станет довольно большим.

person xanatos    schedule 01.03.2016

Следуя ответу Xanatos на С#, слегка измененному для возврата простого массива байтов. Это берет массив байтов, сжатый gzip, и возвращает массив, сжатый с помощью пистолета.

public static byte[] Decompress(byte[] compressed_data)
{
    var outputStream = new MemoryStream();
    using (var compressedStream = new MemoryStream(compressed_data))
    using (System.IO.Compression.GZipStream sr = new System.IO.Compression.GZipStream(
        compressedStream, System.IO.Compression.CompressionMode.Decompress))
    {
        sr.CopyTo(outputStream);
        outputStream.Position = 0;
        return outputStream.ToArray();
    }
}
person Daniel Strickland    schedule 02.10.2020