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类"
生成的文件,
+---+---+---+---+---+---+---+---+---+---+
|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
<梅川酷子原创>
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
用户398633 2011-3-21 17:07