GZip декомпрессия на платформе .NET

При работе с GZip на платформе .NET многие разработчики сталкиваются с проблемой, когда компрессия работает нормально, а при декомпрессии не могут получить исходные данные. На самом деле GZip работает абсолютно нормально, но при одном условии - чтобы декомпрессия работала корректно, нужно знать исходный размер сжимаемых данных.


using System;
using System.IO;
using System.IO.Compression;
using System.Text;

namespace Poligon
{
    /// <summary>
    /// Работа с GZip
    /// </summary>
    public class GZip
    {
        /// <summary>GZip компрессия файла</summary>
        /// <param name="fileName">Имя файла с полным путем</param>
        /// <param name="length">Размер файла до компрессии</param>
        /// <returns>Массив байтов файла после компрессии</returns>
        public static byte[] CompressFile(string fileName, out int length)
        {
            length = 0;
            byte[] buffer;
            if (!File.Exists(fileName))
                throw new FileNotFoundException(fileName);
            using (var fs = new FileStream(fileName,
                FileMode.Open, FileAccess.Read, FileShare.Read)) {
                buffer = new byte[fs.Length];
                for (int i = 0; i < buffer.Length; i++)
                    buffer[i] = (byte)fs.ReadByte();
            }
            length = buffer.Length;
            byte[] result;
            using (var ms = new MemoryStream()) {
                using (var gs = new GZipStream(ms, CompressionMode.Compress))
                    gs.Write(buffer, 0, buffer.Length);
                ms.Close();
                result = ms.ToArray();
            }
            return result;
        }

        /// <summary>GZip декомпрессия файла</summary>
        /// <param name="fileName">Имя файла с полным путем</param>
        /// <param name="data">Массив байтов файла до декомпрессии</param>
        /// <param name="length">Размер файла после декомпрессии</param>
        /// <returns>Результат создания файла</returns>
        public static bool DecompressFile(string fileName, byte[] data, int length)
        {
            byte[] result;
            // Распаковать
            using (var ms = new MemoryStream(data))
            using (var gs = new GZipStream(ms, CompressionMode.Decompress))
            using (var bs = new MemoryStream()) {
                var buffer = new byte[length];
                int read;
                while ((read = gs.Read(buffer, 0, buffer.Length)) > 0)
                    bs.Write(buffer, 0, read);
                bs.Close();
                result = bs.ToArray();
            }
            if (File.Exists(fileName))
                File.Delete(fileName);
            using (var fs = new FileStream(fileName, FileMode.CreateNew))
            using (var bw = new BinaryWriter(fs)) bw.Write(result);
            return File.Exists(fileName);
        }

        /// <summary>GZip компрессия строки</summary>
        /// <param name="data">Исходная строка</param>
        /// <param name="length">Длина строки до компрессии</param>
        /// <returns>Массив байтов строки после компрессии</returns>
        public static byte[] CompressString(string data, out int length)
        {
            byte[] result = null;
            byte[] buffer = Encoding.UTF8.GetBytes(data);
            length = buffer.Length;
            if (string.IsNullOrEmpty(data))
                return result;
            using (var ms = new MemoryStream()) {
                using (var gs = new GZipStream(ms, CompressionMode.Compress))
                    gs.Write(buffer, 0, buffer.Length);
                ms.Close();
                result = ms.ToArray();
            }
            return result;
        }

        /// <summary>GZip декомпрессия строки</summary>
        /// <param name="data">Массив байтов строки до декомпрессии</param>
        /// <param name="length">Длина строки после декомпрессии</param>
        /// <returns>Строка после декомпрессии</returns>
        public static string DecomressString(byte[] data, int length)
        {
            if (data != null) {
                using (var ms = new MemoryStream(data))
                using (var gs = new GZipStream(ms, CompressionMode.Decompress))
                using (var bs = new MemoryStream()) {
                    var buffer = new byte[length];
                    int read;
                    while ((read = gs.Read(buffer, 0, buffer.Length)) > 0)
                        bs.Write(buffer, 0, read);
                    bs.Close();
                    var result = bs.ToArray();
                    if (result.Length != length)
                        throw new InvalidOperationException();
                    return Encoding.UTF8.GetString(result);
                }
            }
            return null;
        }

    }
}

Комментарии