SharpZipLib для сжатия строки - PullRequest
1 голос
/ 23 марта 2012

Мне нужно сжать строку, чтобы уменьшить размер ответа веб-службы.Я вижу модульные тесты в примерах SharpZipLib, но не пример именно того, что мне нужно.

В следующем коде конструктор для ZipOutputStream возвращает исключение: «Нет открытой записи»

        byte[] buffer = Encoding.UTF8.GetBytes(SomeLargeString);
        Debug.WriteLine(string.Format("Original byes of string: {0}", buffer.Length));

        MemoryStream ms = new MemoryStream();
        using (ZipOutputStream zipStream = new ZipOutputStream(ms))
        {
            zipStream.Write(buffer, 0, buffer.Length);
            Debug.WriteLine(string.Format("Compressed byes: {0}", ms.Length));
        }

        ms.Position = 0;
        MemoryStream outStream = new MemoryStream();

        byte[] compressed = new byte[ms.Length];
        ms.Read(compressed, 0, compressed.Length);

        byte[] gzBuffer = new byte[compressed.Length + 4];
        System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4, compressed.Length);
        System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gzBuffer, 0, 4);
        string compressedString = Convert.ToBase64String (gzBuffer);

Где я сбился с пути?Я делаю это более сложным, чем должно быть?

Ответы [ 5 ]

4 голосов
/ 31 декабря 2014

Для данных сжатия веб-службы из Silverlight я использую этот фрагмент:

private byte[] zipText(string text)
{
    if (text == null)
        return null;

    using(Stream memOutput = new MemoryStream())
    {
        using (GZipOutputStream zipOut = new GZipOutputStream(memOutput))
        {
            using (StreamWriter writer = new StreamWriter(zipOut))
            {
                writer.Write(text);

                writer.Flush();
                zipOut.Finish();

                byte[] bytes = new byte[memOutput.Length];
                memOutput.Seek(0, SeekOrigin.Begin);
                memOutput.Read(bytes, 0, bytes.Length);

                return bytes;
            }
        }
    }
}

private string unzipText(byte[] bytes)
{
    if (bytes == null)
        return null;

    using(Stream memInput = new MemoryStream(bytes))
    using(GZipInputStream zipInput = new GZipInputStream(memInput))
    using(StreamReader reader = new StreamReader(zipInput))
    {
        string text = reader.ReadToEnd();

        return text;
    }
}
  1. Я использовал GZip вместо сжатия Zip
  2. Ожидается, что текст будет читаться / записываться изв аналогичной среде, поэтому я не делал никакого дополнительного кодирования / декодирования.

В моем случае было сжатие данных json.Из моих наблюдений в некоторых случаях текстовые данные размером около 95 КБ были сжаты до 1,5 КБ.Так что даже данные будут сериализованы в базу 64, в любом случае это хорошая экономия трафика.

Написал мой ответ, который может кому-то сэкономить время.

3 голосов
/ 23 марта 2012

Вы уверены, что после преобразования в Base 64 данные станут намного меньше? Это значительно расширит двоичные данные (zip). Не можете решить проблему на транспортном уровне с помощью сжатия HTTP?

Вот пост с полным исходным кодом, в котором показано, как выполнить zip / unzip туда и обратно.

http://paultechguy.blogspot.com/2008/09/zip-xml-in-memory-for-web-service.html

2 голосов
/ 23 марта 2012

Несколько проблем с вашим кодом:

  1. Всегда сбрасывайте данные при работе с потоками.

  2. Для чтения данных из MemoryStream, просто используйте:

    byte [] data = ms.ToArray ();

  3. Zip-файлы - это контейнеры, которые могут содержать несколько записей (файлов), комментариев ...вам может потребоваться вызвать PutNextEntry (), чтобы добавить новую запись, прежде чем начинать записывать в нее данные.

  4. Если вам нужно сжать только один поток данных (в вашем случае), ваш лучший выбор - просто использовать сжатие deflate (или gzip), которое предназначено для сжатия одного потока данных (фактически формат zip использует gzip для сжатия своих записей ...) .Net предлагает 2 очень удобных класса для сжатия данных: GZipStream и DeflateStream.Хороший образец можно найти здесь

1 голос
/ 23 марта 2012

Вам нужно вызвать PutNextEntry, чтобы добавить заголовок перед записью данных.

Ответ скопирован с: http://community.sharpdevelop.net/forums/p/5910/16947.aspx

0 голосов
/ 29 марта 2018

Самый простой ответ, который я нашел, - это иметь дело с байтами при распаковке / заархивировании данных и использовать буфер установленного размера для копирования данных в объект Stream, который можно использовать по своему усмотрению:

    /// <summary>
    /// Unzips (inflates) zipped data.
    /// </summary>
    /// <param name="zippedData">The zipped data.</param>
    /// <returns>The inflated data.</returns>
    public Byte[] GUnzip(Byte[] zippedData)
    {
        using (MemoryStream unzippedData = new MemoryStream())
        {
            using (GZipInputStream zippedDataStream = new GZipInputStream(new MemoryStream(zippedData)))
            {
                CopyStream(zippedDataStream, unzippedData);
            }

            return unzippedData.ToArray();
        }
    }

    /// <summary>
    /// zips data.
    /// </summary>
    /// <param name="unzippedData">The unzipped data.</param>
    /// <returns>The zipped data.</returns>
    public Byte[] GZip(Byte[] unzippedData)
    {
        using (MemoryStream zippedData = new MemoryStream())
        {
            using (GZipOutputStream unzippedDataStream = new GZipOutputStream(new MemoryStream(unzippedData)))
            {
                CopyStream(unzippedDataStream, zippedData);
            }

            return zippedData.ToArray();
        }
    }

    /// <summary>
    /// Accepts an inStream, writes it to a buffer and goes out the outStream
    /// </summary>
    /// <param name="inStream">The input Stream</param>
    /// <param name="outStream">The output Stream</param>
    private static void CopyStream(Stream inStream, Stream outStream)
    {
        int nRead = 0;
        // Using a 2k buffer
        Byte[] theBuffer = new Byte[2048];

        while ((nRead = inStream.Read(theBuffer, 0, theBuffer.Length)) > 0)
        {
            outStream.Write(theBuffer, 0, nRead);
        }
    }
...