用DeflateStream和GZipStream压缩数据

本文介绍了.NET Framework中System.IO.Compression命名空间下的GZipStream和DeflateStream两个类的区别与应用。通过示例代码展示了如何使用这两个类进行数据压缩,并详细解释了GZipStream如何在压缩数据前后添加额外信息。


System.IO.Compression 命名空间提供两个类:DeflateStream和GZipStream,这两个类都可以实现数据压缩.这两个类采用都采用Deflate算法来进行无损数据压缩,
下面通过简单的代码来比较两者的差别.Deflate算法的信息,可以从官网http://www.faqs.org/rfcs/rfc1951.html和维基百科
http://zh.wikipedia.org/zh-cn/DEFLATE得到.

 

以下Compress函数通过参数UseDeflateStream来指定用哪个流来生成文件,分别生成以".de"和".gs"为扩展名的文件.   
 Private Function Compress(ByVal FileName As String, ByVal UseDeflateStream As Boolean) As Boolean
        Dim CompressedLen As Integer

 

        Dim Buffer() As Byte = My.Computer.FileSystem.ReadAllBytes(FileName)

 

        Dim ms As New MemoryStream()

 

        If UseDeflateStream Then
            Dim cs As DeflateStream
            cs = New DeflateStream(ms, CompressionMode.Compress, True)
            cs.Write(Buffer, 0, Buffer.Length)
            cs.Close()
            cs.Dispose()
        Else
            Dim cs As GZipStream
            cs = New GZipStream(ms, CompressionMode.Compress, True)
            cs.Write(Buffer, 0, Buffer.Length)
            cs.Close()
            cs.Dispose()
        End If

 

        CompressedLen = ms.Length

 

        Dim NewBuffer() As Byte
        ReDim NewBuffer(ms.Length - 1)

 

        ms.Position = 0
        ms.Read(NewBuffer, 0, CompressedLen)

 

        ms.Close()
        ms.Dispose()

 

        Dim fInfo As New FileInfo(FileName)

 

        Dim NewFileName As String = fInfo.FullName.Replace(fInfo.Extension, IIf(UseDeflateStream, ".de", ".gs"))

 

        My.Computer.FileSystem.WriteAllBytes(NewFileName, NewBuffer, False)
    End Function

 

    Private Sub btnbtnCompress_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCompress.Click
        Compress("C:\Users\Kuge\Documents\Temp\log.txt", True)
        Compress("C:\Users\Kuge\Documents\Temp\log.txt", False)
    End Sub

 

通过比较,GZipStream生成的文件比DeflateStream生成的文件多了18字节的数据,其中10字节位于文件头部,8字节位于文件尾部,这18字节研究是
用来干什么的呢?我们来看看GZIP的文件格式(http://www.gzip.org/zlib/rfc-gzip.html).
 原来,GZipStream采用DeflateStream一模一样的算法,仅仅是在流的头部增加".gz"文件的文件头信息共10个字节,以及尾部的原始文件(压缩前)
的大小和原始文件的CRC32校验值,中间的压缩数据部分完全一致,如图所示,左边为调用"DeflateStream类"生成的文件,左边为调用"GZipStream类"
生成的文件,
 

 

98d84d39-8b39-40c5-8ffb-bdb45a806e03.JPG

 

+---+---+---+---+---+---+---+---+---+---+
|ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
+---+---+---+---+---+---+---+---+---+---+
 
参照GZIP格式文档,文件开头1FH,8BH为GZ格式文件的标记ID1,ID2,08H为压缩模式CM等,以此类推;文件结尾的353A7F57H
则表示原始文件的CRC校验值,此值可以借助WINRAR等压缩软件得到,也可以编写程序计算,官方推荐CRC算法代码,0000047F则
表示原始文件的大小为1151字节.
 可见,System.IO.Compression 命名空间的两个类:DeflateStream和GZipStream其用途是不同的.DeflateStream适合于
通信传输压缩,或者自定义文件格式的场合,其数据流仅仅是压缩后的数据流,不包含任何文件类型信息和原始数据文件大小及
校验信息;而GZipStream则在流的头部加入了GZIP格式文件的头,以及原始文件校验值,原始文件大小信息,将流保存成文件可以
被流行的压缩软件WINRAR,7-ZIP,WINZIP等解压,非常方便.
 事实上,GZipStream缺少原始文件名的信息,我们可以修改文件头标志,然后在文件头后面再增加若干字节,用于存储文件名
,这样压缩出来的软件在被WINRAR解压之后,就能还原出原始文件名了.以下是示例代码,供参考.注意,此实例不适合体积大的文件和
压缩之后的文件.
 

 

    Private Function CompressByGZipStream(ByVal FileName As String) As Boolean
        Dim i As Integer
        Dim CompressedLen As Integer

 

        Dim Buffer() As Byte = My.Computer.FileSystem.ReadAllBytes(FileName)

 

        Dim ms As New MemoryStream()
        Dim cs As GZipStream
        cs = New GZipStream(ms, CompressionMode.Compress, True)
        cs.Write(Buffer, 0, Buffer.Length)
        cs.Close()
        cs.Dispose()
        CompressedLen = ms.Length

 

        Dim FileNameSize As Integer
        Dim FileNameBuffer() As Byte
        Dim fInfo As New FileInfo(FileName)
        FileNameBuffer = System.Text.Encoding.Default.GetBytes(fInfo.Name)
        FileNameSize = FileNameBuffer.Length + 1

 

        Dim NewBuffer() As Byte
        ReDim NewBuffer(FileNameSize + ms.Length - 1)

 


        ms.Position = 0
        ms.Read(NewBuffer, 0, 10)

 

        For i = 0 To FileNameBuffer.Length - 1
            NewBuffer(10 + i) = FileNameBuffer(i)
        Next

 

        NewBuffer(10 + FileNameBuffer.Length) = 0 '文件名尾部
        NewBuffer(3) = 8
        ms.Read(NewBuffer, FileNameSize + 10, CompressedLen - 10)

 

        ms.Close()
        ms.Dispose()

 


        Dim NewFileName As String = fInfo.FullName.Replace(fInfo.Extension, ".gz")

 

        My.Computer.FileSystem.WriteAllBytes(NewFileName, NewBuffer, False)
    End Function

 


 9d1aa83c-40dd-41e1-8525-8948d9d1dd1b.JPG

 


MS .NET Framework 4.0 压缩数据更加方便,可以将输入流通过copyto文法,直接输出到压缩流,然后通过输出流输出到文件,只需要若干行代码即可完成压缩大文件的整个过程.MS .NET Framework 4.0 的代码如下所示:

 

输入流-->压缩流-->输出流

 

    ''' <summary>
    ''' 输入流-->压缩流-->输出流
    ''' </summary>
    ''' <param name="FileName"></param>
    ''' <remarks></remarks>
    Private Sub CompressToGZip(ByVal FileName As String)
        Dim InputFileInfo As New FileInfo(FileName)
        Dim OutputFileInfo As New FileInfo(FileName.Replace(InputFileInfo.Extension, ".gz"))
        Using 输入文件流 As FileStream = InputFileInfo.OpenRead
            Using 输出文件流 As FileStream = File.Create(OutputFileInfo.FullName)
                Using 压缩流 As New System.IO.Compression.GZipStream(输出文件流, Compression.CompressionMode.Compress, True)
                    输入文件流.CopyTo(压缩流) '从输入文件流读取所有字节并写到压缩流,由输出流输出到文件
                End Using
            End Using
        End Using
    End Sub

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值