图片 2

Java和.NET的GZIP压缩功能对比

本文由码农网 –
王国峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

压缩文本、字节或者文件的压缩辅助类-GZipHelper 欢迎收藏
下面为大家介绍一.NET下辅助公共类GZipHelper,该工具类主要作用是对文本、字符、文件等进行压缩与解压。该类主要使用命名空间:System.IO.Compression下的GZipStream类来实现。
此类表示 GZip
数据格式,它使用无损压缩和解压缩文件的行业标准算法。这种格式包括一个检测数据损坏的循环冗余校验值。GZip
数据格式使用的算法与 DeflateStream
类的算法相同,但它可以扩展以使用其他压缩格式。这种格式可以通过不涉及专利使用权的方式轻松实现。gzip
的格式可以从 RFC 1952“GZIP file format specification 4.3(GZIP
文件格式规范 4.3)GZIP file format specification 4.3(GZIP 文件格式规范
4.3)”中获得。此类不能用于压缩大于 4 GB 的文件。
一、属性
BaseStream获取对基础流的引用。
CanRead获取一个值,该值指示流是否支持在解压缩文件的过程中读取文件。
(重写 Stream..::.CanRead。)
CanSeek获取一个值,该值指示流是否支持查找。 (重写
Stream..::.CanSeek。)
CanTimeout获取一个值,该值确定当前流是否可以超时。 (继承自
Stream。)
CanWrite获取一个值,该值指示流是否支持写入。 (重写
Stream..::.CanWrite。)
Length不支持,并且总是引发 NotSupportedException。 (重写
Stream..::.Length。)
Position不支持,并且总是引发 NotSupportedException。 (重写
Stream..::.Position。)
ReadTimeout获取或设置一个值(以毫秒为单位),该值确定流在超时前尝试读取多长时间。
(继承自 Stream。)
WriteTimeout获取或设置一个值(以毫秒为单位),该值确定流在超时前尝试写入多长时间。
(继承自 Stream。)
二、方法
BeginRead开始异步读操作。 (重写
Stream..::.BeginRead(array[],
Int32, Int32, AsyncCallback, Object)。)
BeginWrite开始异步写操作。 (重写
Stream..::.BeginWrite(array[],
Int32, Int32, AsyncCallback, Object)。)
Close关闭当前流并释放与之关联的所有资源(如套接字和文件句柄)。
(继承自 Stream。)
CreateObjRef创建一个对象,该对象包含生成用于与远程对象进行通信的代理所需的全部相关信息。
(继承自 MarshalByRefObject。)
Dispose已重载。
EndRead等待挂起的异步读取完成。 (重写
Stream..::.EndRead(IAsyncResult)。)
EndWrite处理异步写入的结束。 (重写
Stream..::.EndWrite(IAsyncResult)。)
Flush将当前 GZipStream 对象的内部缓冲区的内容刷新到基础流。 (重写
Stream..::.Flush()()()。)
GetHashCode用作特定类型的哈希函数。 (继承自 Object。)
GetLifetimeService检索控制此实例的生存期策略的当前生存期服务对象。
(继承自 MarshalByRefObject。)
InitializeLifetimeService获取控制此实例的生存期策略的生存期服务对象。
(继承自 MarshalByRefObject。)
MemberwiseClone已重载。
Read将若干解压缩的字节读入指定的字节数组。 (重写
Stream..::.Read(array[],
Int32, Int32)。)
ReadByte从流中读取一个字节,并将流内的位置向前推进一个字节,或者如果已到达流的末尾,则返回
-1。 (继承自 Stream。)
Seek此属性不受支持,并且总是引发 NotSupportedException。 (重写
Stream..::.Seek(Int64, SeekOrigin)。)
SetLength此属性不受支持,并且总是引发 NotSupportedException。 (重写
Stream..::.SetLength(Int64)。)
Write从指定的字节数组中将压缩的字节写入基础流。 (重写
Stream..::.Write(array[],
Int32, Int32)。)
WriteByte将一个字节写入流内的当前位置,并将流内的位置向前推进一个字节。
(继承自 Stream。)
使用原生的方法进行压缩解压文件实例代码:
`/// <summary> /// 压缩文件 /// </summary> /// <param name="fileName">文件名(全路径)</param> /// <param name="data">需要压缩的字符串</param> public void CompressFile(string fileName, string data) { FileStream fstream = new FileStream(fileName, FileMode.Create, FileAccess.Write); GZipStream gstream = new GZipStream(fstream, CompressionMode.Compress); StreamWriter swriter = new StreamWriter(gstream); swriter.Write(data); swriter.Close(); gstream.Close(); fstream.Close(); } /// <summary> /// 解压缩 /// </summary> /// <param name="fileName">文件名(全路径)</param> /// <returns></returns> public string DecompressFile(string fileName) { string cstring=""; FileStream fstream = new FileStream(fileName, FileMode.Open, FileAccess.Read); GZipStream gstream = new GZipStream(fstream, CompressionMode.Decompress); StreamReader reader = new StreamReader(gstream); cstring=reader.ReadToEnd(); reader.Close(); gstream.Close(); fstream.Close(); return cstring; }`
GZipHelper公共类就是以GZipStream类为基础做的对常用解压缩进行的封装。GZipHelper类图如下所示:
[图片上传中。。。(1)]
GZipHelper公共类完整源码:
`
using System;
using System.IO;
using System.IO.Compression;
using System.Text;

本文主要比较了Java和.NET提供的GZIP压缩功能。

namespace RDIFramework.Utilities
{
/// <summary>
/// 压缩文本、字节或者文件的压缩辅助类
/// </summary>
public class GZipHelper
{
/// <summary>
/// 压缩字符串
/// </summary>
/// <param name=”text”></param>
/// <returns></returns>
public static string Compress(string text)
{
// convert text to bytes
byte[] buffer = Encoding.UTF8.GetBytes(text);
// get a stream
MemoryStream ms = new MemoryStream();
// get ready to zip up our stream
using (GZipStream zip = new GZipStream(ms, CompressionMode.Compress,
true))
{
// compress the data into our buffer
zip.Write(buffer, 0, buffer.Length);
}
// reset our position in compressed stream to the start
ms.Position = 0;
// get the compressed data
byte[] compressed = ms.ToArray();
ms.Read(compressed, 0, compressed.Length);
// prepare final data with header that indicates length
byte[] gzBuffer = new byte[compressed.Length + 4];
//copy compressed data 4 bytes from start of final header
System.Buffer.BlockCopy(compressed, 0, gzBuffer, 4,
compressed.Length);
// copy header to first 4 bytes
System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0,
gzBuffer, 0, 4);
// convert back to string and return
return Convert.ToBase64String(gzBuffer);
}

介绍

在本文中,我们将讨论Java和.NET提供的GZIP压缩功能,并且用实例来说明哪个压缩方法更佳。

在Java中,我们有提供GZIP压缩的GZIPOutputStream类,这个类在Java.util.zip包中。而在.NET中,我们有执行GZIP压缩的GZipStream类,这个类在System.IO.Compression命名空间下。

我这里所说的更好方法针对的是小尺寸文件,因为我已经检验过小文件的效果,比如说当我们想在发送之前压缩我们的信息文件。

    /// <summary>
    /// 解压字符串
    /// </summary>
    /// <param name="compressedText"></param>
    /// <returns></returns>
    public static string Uncompress(string compressedText)
    {
        // get string as bytes
        byte[] gzBuffer = Convert.FromBase64String(compressedText);
        // prepare stream to do uncompression
        MemoryStream ms = new MemoryStream();
        // get the length of compressed data
        int msgLength = BitConverter.ToInt32(gzBuffer, 0);
        // uncompress everything besides the header
        ms.Write(gzBuffer, 4, gzBuffer.Length - 4);
        // prepare final buffer for just uncompressed data
        byte[] buffer = new byte[msgLength];
        // reset our position in stream since we're starting over
        ms.Position = 0;
        // unzip the data through stream
        GZipStream zip = new GZipStream(ms, CompressionMode.Decompress);
        // do the unzip
        zip.Read(buffer, 0, buffer.Length);
        // convert back to string and return
        return Encoding.UTF8.GetString(buffer);
    }

    public static T GZip<T>(Stream stream, CompressionMode mode) where T : Stream
    {
        byte[] writeData = new byte[4096];
        T ms = default(T);
        using (Stream sg = new GZipStream(stream, mode))
        {
            while (true)
            {
                Array.Clear(writeData, 0, writeData.Length);
                int size = sg.Read(writeData, 0, writeData.Length);
                if (size > 0)
                {
                    ms.Write(writeData, 0, size);
                }
                else
                {
                    break;
                }
            }
            return ms;
        }
    }

    /// <summary>
    /// 压缩字节
    /// </summary>
    /// <param name="bytData"></param>
    /// <returns></returns>
    public static byte[] Compress(byte[] bytData)
    {
        using (MemoryStream stream = GZip<MemoryStream>(new MemoryStream(bytData), CompressionMode.Compress))
        {
            return stream.ToArray();
        }
    }

    /// <summary>
    /// 解压字节
    /// </summary>
    /// <param name="bytData"></param>
    /// <returns></returns>
    public static byte[] Decompress(byte[] bytData)
    {
        using (MemoryStream stream = GZip<MemoryStream>(new MemoryStream(bytData), CompressionMode.Decompress))
        {
            return stream.ToArray();
        }
    }

    /// <summary>
    /// 压缩文件
    /// </summary>
    /// <param name="sourceFile">源文件</param>
    /// <param name="destinationFile">目标文件</param>
    public static void CompressFile(string sourceFile, string destinationFile)
    {
        if (File.Exists(sourceFile) == false) //判断文件是否存在
            throw new FileNotFoundException();
        if (File.Exists(destinationFile) == false) //判断目标文件文件是否存在
            FileHelper.FileDel(destinationFile);
        //创建文件流和字节数组
        byte[] buffer = null;
        FileStream sourceStream = null;
        FileStream destinationStream = null;
        GZipStream compressedStream = null;
        try
        {
            sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read);
            buffer = new byte[sourceStream.Length];
            //把文件流存放到字节数组中
            int checkCounter = sourceStream.Read(buffer, 0, buffer.Length);
            if (checkCounter != buffer.Length)
            {
                throw new ApplicationException();
            }
            destinationStream = new FileStream(destinationFile, FileMode.OpenOrCreate, FileAccess.Write);
            //创建GzipStream实例,写入压缩的文件流
            compressedStream = new GZipStream(destinationStream, CompressionMode.Compress, true);
            compressedStream.Write(buffer, 0, buffer.Length);
        }
        finally
        {
            // Make sure we allways close all streams
            if (sourceStream != null)
            { sourceStream.Close(); }
            if (compressedStream != null)
            { compressedStream.Close(); }
            if (destinationStream != null)
            { destinationStream.Close(); }
        }
    }

    /// <summary>
    /// 解压文件
    /// </summary>
    /// <param name="sourceFile">源文件</param>
    /// <param name="destinationFile">目标文件</param>
    public static void DecompressFile(string sourceFile, string destinationFile)
    {
        if (!File.Exists(sourceFile))
        {
            throw new FileNotFoundException();
        }
        FileStream stream = null;
        FileStream stream2 = null;
        GZipStream stream3 = null;
        byte[] buffer = null;
        try
        {
            stream = new FileStream(sourceFile, FileMode.Open);
            stream3 = new GZipStream(stream, CompressionMode.Decompress, true);
            buffer = new byte[4];
            int num = ((int)stream.Length) - 4;
            stream.Position = num;
            stream.Read(buffer, 0, 4);
            stream.Position = 0L;
            byte[] buffer2 = new byte[BitConverter.ToInt32(buffer, 0) + 100];
            int offset = 0;
            int count = 0;
            while (true)
            {
                int num5 = stream3.Read(buffer2, offset, 100);
                if (num5 == 0)
                {
                    break;
                }
                offset += num5;
                count += num5;
            }
            stream2 = new FileStream(destinationFile, FileMode.Create);
            stream2.Write(buffer2, 0, count);
            stream2.Flush();
        }
        finally
        {
            if (stream != null)
            {
                stream.Close();
            }
            if (stream3 != null)
            {
                stream3.Close();
            }
            if (stream2 != null)
            {
                stream2.Close();
            }
        }
    }
}

代码解析

1)Java GZIPOutputStream类

该GZIPOutputStream类为压缩数据在GZIP格式文件中创建了输入流。这个类有以下几种的构造函数:

1.创建具有默认大小的输出流:

GZIPOutputStream(OutputStream out);

2.创建新的具有默认缓冲区大小和指定刷新模式的输出流:

GZIPOutputStream(OutputStream out,boolean syncFlush);

3.创建新的具有指定缓冲区大小的输出流:

GZIPOutputStream(OutputStream out,int size);

4.创建新的具有指定的缓冲区大小和刷新模式的输出流:

GZIPOutputStream(OutputStream out,int size,boolean syncFlush);

我们需要编写以下代码来压缩文件:

import java.io.*;
import java.util.zip.*;

class abc{

    public static void main(String args[])
     {
        String srcfile="D:/abhi.txt";
            String dstfile="D:/abhi1.txt";

        try{

            FileInputStream fin= new FileInputStream(srcfile);
                GZIPOutputStream fout=new GZIPOutputStream(new FileOutputStream(dstfile));

                byte[] buffer = new byte[1024];
                int bytesRead;

                while ((bytesRead = fin.read(buffer)) != -1) //srcfile.getBytes()
                {
                  fout.write(buffer, 0, bytesRead);
                }

                  fin.close();
                  fout.close();

                     File file =new File(srcfile);
                     System.out.println("Before Compression file Size : 
                        " + file.length()+" Bytes");
                     File file1 =new File(dstfile);
                     System.out.println("After Compression file Size : 
                        " + file1.length()+" Bytes");

     }catch(Exception ex)
       {
        System.out.println(ex);
       }
   }

}

运行代码。输出如下,因为我提供的源文件只有481个字节大小,然后经过压缩后输出的文件大小为207个字节。

图片 1

现在,我们用相同的输入文件来看看GZIP压缩后的效果。

2).NET GZipStream类

GZipStream压缩string或文件。它可以让你有效地保存数据,如压缩日志文件,消息文件。这个类存在于System.IO.Compression的命名空间。它创建GZIP文件,并将其写入磁盘。

GZipStream类提供以下构造函数:

1.通过使用指定字节流和压缩等级初始化GZipStream类的新实例:

GZipStream(Stream, CompressionLevel)

2.通过使用指定流和压缩模式初始化GZipStream类的新实例:

GZipStream(Stream, CompressionMode)

3.通过使用指定流和压缩等级初始化GZipStream类的新实例,并可选是否打开流:

GZipStream(Stream, CompressionLevel, Boolean)

4.通过使用指定流和压缩模式初始化GZipStream类的新实例,并可选是否打开流:

GZipStream(Stream, CompressionMode, Boolean)

我们需要编写以下代码来压缩文件:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Compression;

namespace Compress
{
    class Program
    {
        static void Main(string[] args)
        {
            string srcfile = "D:\abhi.txt";
            string dstfile = "D:\abhi2.txt";

            byte[] b;

            using (FileStream f = new FileStream(srcfile, FileMode.Open))
            {
                b = new byte[f.Length];
                f.Read(b, 0, (int)f.Length);
            }

            using (FileStream fs = new FileStream(dstfile, FileMode.Create))

            using (GZipStream gzip = new GZipStream(fs, CompressionMode.Compress, false))
            {
                gzip.Write(b, 0, b.Length);
            }

            FileInfo f2 = new FileInfo(srcfile);
            System.Console.WriteLine("Size Of File Before Compression :"+f2.Length);

            FileInfo f1 = new FileInfo(dstfile);
            System.Console.WriteLine("Size Of File Before Compression :" + f1.Length); 
        }
}

运行代码。输出如下,由于我提供的是481字节大小的源文件,然后压缩后的输出文件大小为353个字节。

图片 2

大家可以看到,源文件为481字节,压缩文件大小为:

  1.  .NET的GzipStream:353字节
  2. Java的GZIPOutputStream :207字节

压缩后的尺寸大小差距很明显。因此,我们可以得出结论,Java的GZIP压缩比.NET更好。

}
`

兴趣点

我是在使用IKVM.NET研究Java和.NET之间的互操作性时发现的。我认为这很有意思,所以分享给大家。

发表评论

电子邮件地址不会被公开。 必填项已用*标注