Ошибка распаковки: неверное магическое число в заголовке GZip

Я новичок в System.IO.Compression

Я пытаюсь сжать и распаковать некоторую информацию.

Для сжатия я использовал код проекта, и он, кажется, работает. Я сжимаю строку в данный момент.

Для декомпрессии я бы хотел Stream

Это то, что у меня есть на данный момент

        var zipString = _compressor.Compress(request);
        using (var sw = new StreamWriter(req.GetRequestStream()))
        {
            sw.Write(zipString);
            sw.Close();
        }

        WebResponse respStream = req.GetResponse();
        Stream resp = respStream.GetResponseStream();                      
        resp = _compressor.UnCompress(resp);

Вот код длясжатия

    public string Compress(string s)
    {
        //Transforming string into byte
        var byteArray = new byte[s.Length];
        var indexBa = 0;
        foreach (var item in s.ToCharArray())
        {
            byteArray[indexBa++] = (byte) item;
        }

        //prepare for compress
        var ms = new MemoryStream();
        var sw = new GZipStream(ms, CompressionMode.Compress);

        //compress
        sw.Write(byteArray,0,byteArray.Length);

        //close sw, DO NOT FLUSH because byes will go missing...
        sw.Close();

        //transform byte[] zip data to string
        byteArray = ms.ToArray();
        var sb = new StringBuilder(byteArray.Length);
        foreach (var item in byteArray)
        {
            sb.Append((char) item);
        }
        ms.Close();
        sw.Dispose();
        ms.Dispose();
        return sb.ToString();
    }

А вот код дляраспаковки

    public Stream UnCompress(Stream s)
    {
        int readCount;
        MemoryStream mem = new MemoryStream();
        byte[] tmp = new byte[128];
        while ((readCount = s.Read(tmp, 0, 128)) != 0)
        {
            mem.Write(tmp, 0, readCount);
        }
        StreamReader reader = new StreamReader(mem);
        char[] buffer = new char[mem.Length];
        mem.Position = 0;
        reader.ReadBlock(buffer, 0, (int)mem.Length);

        byte[] zip = Encoding.UTF8.GetBytes(buffer, 0, (int)mem.Length);
        Stream wr = new MemoryStream();
        wr.Write(zip, 0, zip.Length);
        wr.Position = 0;
        using (var stream = new GZipStream(wr, CompressionMode.Decompress))
        {                
            mem = new MemoryStream();
            while ((readCount = stream.Read(tmp, 0, 128)) != 0)
            {
                mem.Write(tmp, 0, readCount);
            }
            mem.Position = 0;
            return mem;
        }        
    }

В этот момент я получаю ошибку при распаковке в следующей строке:

while ((readCount = stream.Read(tmp, 0, 128)) != 0)
{
     mem.Write(tmp, 0, readCount);
}

Он просто не входит в цикл while и говорит:

Магическое число в заголовке GZip неверно.Убедитесь, что вы передаете поток GZip

Мой метод распаковки основан на следующем сообщении stackru

Попробуйте 2:

        public Stream UnCompress(Stream s)
        {
            byte[] byteArray = null;
            using (var m = new MemoryStream())
            {
                int count;
                do
                {
                    byte[] buf = new byte[1024];
                    count = s.Read(buf, 0, 1024);
                    m.Write(buf, 0, count);
                } while (s.CanRead && count > 0);
                byteArray = m.ToArray();
            }
            var indexBa = 0;
            foreach (var item in s.ToString().ToCharArray())
            {
                byteArray[indexBa++] = (byte) item;
            }
            //Prepare for decompress
            var ms = new MemoryStream(byteArray);
            var sr = new GZipStream(ms,
                CompressionMode.Decompress);

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

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

            //Transform byte[] unzip data to string
            var sB = new MemoryStream(rByte);

            for (var i = 0; i < rByte; i++)
            {
                sB.Write(byteArray,0,rByte);
            }
            sr.Close();
            ms.Close();
            sr.Dispose();
            ms.Dispose();
            return sB;
        }

Результат: та же ошибка в строке var rByte = sr.Read(byteArray, 0, byteArray.Length);Обновление 1:

Как указано в коде проекта, декомпрессионная строка прекрасно работает.

public static string UnZip(string value)
{
    //Transform string into byte[]
    byte[] byteArray = new byte[value.Length];
    int indexBA = 0;
    foreach (char item in value.ToCharArray())
    {
        byteArray[indexBA++] = (byte)item;
    }

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

1 ответ

Решение

В вашем коде много проблем, поэтому проще написать еще одну версию с нуля. Обратите внимание, что делать это:

var byteArray = new byte[s.Length];
var indexBa = 0;
foreach (var item in s.ToCharArray())
{
    byteArray[indexBa++] = (byte) item;
}

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

Образец кода:

static byte[] Compress(byte[] data) {
    // `compressed` will contain result of compression
    using (var compressed = new MemoryStream()) {
        // source is our original uncompressed data
        using (var source = new MemoryStream(data)) {
            using (var gzip = new GZipStream(compressed, CompressionMode.Compress)) {
                // just write whole source into gzip stream with CopyTo
                source.CopyTo(gzip);
            }
        }
        return compressed.ToArray();
    }
}

static byte[] CompressString(string s, Encoding encoding) {
    return Compress(encoding.GetBytes(s));
}

static string CompressStringToBase64(string s, Encoding encoding) {
    return Convert.ToBase64String(CompressString(s, encoding));
}

static byte[] Decompress(Stream source) {
    using (var gzip = new GZipStream(source, CompressionMode.Decompress)) {
        using (var decompressed = new MemoryStream()) {
            gzip.CopyTo(decompressed);
            return decompressed.ToArray();
        }
    }
}

static byte[] Decompress(byte[] data) {
    using (var ms = new MemoryStream(data)) {
        return Decompress(ms);
    }
}

static string DecompressString(Stream source, Encoding encoding) {
    return encoding.GetString(Decompress(source));
}

Тестовое задание

var source = "Some string";
var compressed = CompressString(source, Encoding.UTF8);            
var decompressed = DecompressString(new MemoryStream(compressed), Encoding.UTF8);
Debug.Assert(source == decompressed);
Другие вопросы по тегам