摘要 如果你的应用程序从未使用过压缩,那么你很幸运。而对于另一部分使用压缩的开发人员来说,好消息是,.NET 2.0如今提供了两个类来处理压缩和解压问题。本文正是想讨论何时以及如何使用这些有用的工具。
引言
.NET框架2.0中的一个新名称空间是System.IO.Compression。这个新名称空间提供了两个数据压缩类:DeflateStream和GZipStream。这两个压缩类都支持无损压缩和解压,其设计目的是为了处理流式数据的压缩和解压问题。
压缩是减少数据大小的有效办法。例如,如果你有巨大量的数据存储在你的SQL数据库中,那么如果你在把这些数据保存到一个表之前压缩一下,你就可以节省大量的磁盘空间。而且,既然现在你把更小块的数据保存到你的数据库中,花费在磁盘I/O方面的操作将会大大减少。压缩的缺点是,它要求你的机器进行另外的处理(因此需要另外的处理时间),并且,在你决定把压缩应用于你的程序之前,你需要计算这一部分时间。
压缩在你需要在网上传送数据的情况中是极其有用的,特别是对于非常慢且代价昂贵的网络,例如GPRS连接。在这种情况中,使用压缩能够极大地缩小数据尺寸并且减少整个通讯耗费。Web服务是另一个领域-此时,使用压缩能提供巨大的优点,因为XML数据能被高度压缩。
但是一旦你认为程序的性能代价值得使用压缩,那么你将需要深入地理解.NET 2.0的两个新的压缩类,而这正是我想在本文中所阐述的。
创建示例应用程序
在本文中,我将构建一个示例应用程序来展示压缩的使用。该应用程序允许你压缩文件,包括普通文本文件。然后,你能够把该示例中的代码重用于你自己的应用程序中。
首先,使用Visual Studio 2005创建一个新的Windows应用程序并且使用下列控件来填充默认的表单(见图1):
图1.填充表单:使用所有显示的控件填充默认的Form1。
· GroupBox控件
· RadioButton控件
· TextBox控件
· Button控件
· Label控件
切换到Form1的code-behind并且导入下列名称空间:
Imports System.IO
Imports System.IO.Compression
在你开始使用压缩类前,理解其工作原理是非常重要的。这些压缩类从一个字节数组中读取数据,压缩它并且把结果存储到一个流对象中。对于解压来说,解压存储到一个流对象中的数据,然后把它存储到另一个流对象中。
首先,定义Compress()函数,它有两个参数:algo和data。第一个参数指定使用哪种算法(GZip或Deflate);第二个参数是一个包含要压缩的数据的字节数组。一个内存流对象将被用来存储压缩数据。一旦压缩完成,你需要计算压缩比,这是用压缩的数据的大小除以解压数据的大小计算的。
然后,存储在内存流中的压缩的数据被复制到另一个字节数组中并且被返回到调用函数。另外,你还要使用一个StopWatch对象来跟踪该压缩算法使用了多少时间。Compress()函数定义如下:
Public Function Compress(ByVal algo As String, ByVal data() As Byte) As Byte()
Try
Dim sw As New Stopwatch
'---ms用于存储压缩的数据---
Dim ms As New MemoryStream()
Dim zipStream As Stream = Nothing
'---开始秒表计时---
sw.Start()
If algo = "Gzip" Then
zipStream = New GZipStream(ms, CompressionMode.Compress, True)
ElseIf algo = "Deflate" Then
zipStream = New DeflateStream(ms, CompressionMode.Compress, True)
End If
'---使用存储在数据中的信息进行压缩---
zipStream.Write(data, 0, data.Length)
zipStream.Close()
'---停止秒表---
sw.Stop()
'---计算压缩比---
Dim ratio As Single = Math.Round((ms.Length / data.Length) * 100, 2)
Dim msg As String = "Original size: " & data.Length & _
", Compressed size: " & ms.Length & _
", 压缩比: " & ratio & "%" & _
", Time spent: " & sw.ElapsedMilliseconds & "ms"
lblMessage.Text = msg
ms.Position = 0
'---用来存储压缩了的数据(字节数组)---
Dim c_data(ms.Length - 1) As Byte
'---把内存流的内容读取到字节数组---
ms.Read(c_data, 0, ms.Length)
Return c_data
Catch ex As Exception
MsgBox(ex.ToString)
Return Nothing
End Try
End Function
这个Decompress()函数将解压由Compress()函数压缩的数据。第一个参数指定要使用的算法。包含压缩的数据的字节数组被作为第二个参数传递,然后它被复制到一个内存流对象中。然后,这些压缩类将解压存储在内存流中的数据,然后把解压的数据存储到另一个流对象中。为了获得解压的数据,你需要读取来自流对象的数据。这是通过使用RetrieveBytesFromStream()函数来实现的(将在后面解释)。
Decompress()函数的定义如下所示:
Public Function Decompress(ByVal algo As String, ByVal data() As Byte) As Byte()
Try
Dim sw As New Stopwatch
'---复制数据(压缩的)到ms---
Dim ms As New MemoryStream(data)
Dim zipStream As Stream = Nothing
'---开始秒表---
sw.Start()
'---使用存储在ms中的数据解压---
If algo = "Gzip" Then
zipStream = New GZipStream(ms, CompressionMode.Decompress)
ElseIf algo = "Deflate" Then
zipStream = New DeflateStream(ms, CompressionMode.Decompress, True)
End If
'---用来存储解压的数据---
Dim dc_data() As Byte
'---解压的数据存储于zipStream中;
'把它们提取到一个字节数组中---
dc_data = RetrieveBytesFromStream(zipStream, data.Length)
'---停止秒表---
sw.Stop()
lblMessage.Text = "Decompression completed. Time spent: " & _
sw.ElapsedMilliseconds & "ms" & _
", Original size: " & dc_data.Length
Return dc_data
Catch ex As Exception
MsgBox(ex.ToString)
Return Nothing
End Try
End Function
这个RetrieveBytesFromStream()函数使用了两个参数:一个流对象,一个整数,并返回一个包含解压的数据的字节数组。这个整数参数用于决定每次把多少个字节从该流对象中读取到字节数组中。这是必要的,因为当数据被解压时,你不知道存在于流对象中的解压数据的大小。因此,有必要动态地把字节数组扩展成块以便存储在运行时刻期间解压缩的数据中。当你不断地扩展字节数组时,块太大会浪费内存,而块太小则会失去珍贵的时间。因此,可以由调用例程来决定要读取的最佳块大小。
RetrieveBytesFromStream()函数的定义如下:
Public Function RetrieveBytesFromStream( _
ByVal stream As Stream, ByVal bytesblock As Integer) As Byte()
'---从一个流对象中检索字节---
Dim data() As Byte
Dim totalCount As Integer = 0
Try
While True
'---逐渐地增加数据字节数组-的大小--
ReDim Preserve data(totalCount + bytesblock)
Dim bytesRead As Integer = stream.Read(data, totalCount, bytesblock)
If bytesRead = 0 Then
Exit While
End If
totalCount += bytesRead
End While
'---确保字节数组正确包含提取的字节数---
ReDim Preserve data(totalCount - 1)
Return data
Catch ex As Exception
MsgBox(ex.ToString)
Return Nothing
End Try
End Function
注意,在Decompress()函数中,你调用了RetrieveBytesFromStream()函数,如下所示:
dc_data = RetrieveBytesFromStream(zipStream, data.Length)
块大小是指压缩的数据的大小(data.length)。在大多数情况中,解压缩的数据要比压缩的数据大几倍(由压缩比所显示),因此,在运行时刻期间你将至多动态地扩展字节数组几倍。作为一个例子,假定压缩比是百分之20而压缩的数据的大小为2MB,那么,在这种情况中,解压的数据将是10MB。因此,该字节数组将被动态地扩展5倍。理想情况下,在运行时刻期间该字节数组不应该被扩展太频繁,因为这将会严重地减慢应用程序运行速度。但是使用压缩的数据的大小作为块大小确是一种好的办法。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。
更新日志
- 中国武警男声合唱团《辉煌之声1天路》[DTS-WAV分轨]
- 紫薇《旧曲新韵》[320K/MP3][175.29MB]
- 紫薇《旧曲新韵》[FLAC/分轨][550.18MB]
- 周深《反深代词》[先听版][320K/MP3][72.71MB]
- 李佳薇.2024-会发光的【黑籁音乐】【FLAC分轨】
- 后弦.2012-很有爱【天浩盛世】【WAV+CUE】
- 林俊吉.2012-将你惜命命【美华】【WAV+CUE】
- 晓雅《分享》DTS-WAV
- 黑鸭子2008-飞歌[首版][WAV+CUE]
- 黄乙玲1989-水泼落地难收回[日本天龙版][WAV+CUE]
- 周深《反深代词》[先听版][FLAC/分轨][310.97MB]
- 姜育恒1984《什么时候·串起又散落》台湾复刻版[WAV+CUE][1G]
- 那英《如今》引进版[WAV+CUE][1G]
- 蔡幸娟.1991-真的让我爱你吗【飞碟】【WAV+CUE】
- 群星.2024-好团圆电视剧原声带【TME】【FLAC分轨】