Chinaunix首页 | 论坛 | 博客
  • 博客访问: 188397
  • 博文数量: 106
  • 博客积分: 3810
  • 博客等级: 中校
  • 技术积分: 1007
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-18 13:35
文章分类

全部博文(106)

文章存档

2014年(17)

2011年(5)

2010年(75)

2009年(9)

我的朋友

分类:

2010-04-26 17:30:41

Imports System
Imports System.Collections.Generic
Imports System.IO
Imports System.IO.Compression


' 此类是一个读取器,它会读取文件基底数据流以便一个接着一个取得压缩文件中项目。
' 压缩文件项目内含文件名称、大小、压缩后的大小、CRC...等信息。
' 它同时支持 GZIP 与 DEFLATE 这两种压缩方式。

Public Class ZipReader '更多.net源码和教程,来自[乐博网 www.lob.cn]
    ' 此封存数据流会在每一次操作之后被初始化与关闭。
    Private zipStream As Stream
    ' 封存的名称。
    Private zipName As String
    ' 被读取之标头与压缩数据的数据流。
    Private baseStream As Stream
    Private numberOfFiles As Int16
    Private thisMethod As Byte

    Private md5 As System.Security.Cryptography.MD5CryptoServiceProvider

    ' 用于检查 CRC 。
    ' 建立一个新的封存输入数据流,读取一个压缩文件。
    Public Sub New(ByVal fileStream As Stream, ByVal name As String)
        zipName = name
        baseStream = fileStream
        numberOfFiles = -1
        thisMethod = 255
        md5 = New System.Security.Cryptography.MD5CryptoServiceProvider()

    End Sub 'New


    ' 读取超标头。
    ' 超标头结构:
    ' 文件的数目 - 2 字节
    ' 压缩的方式 - 1 字节
    Private Sub ReadSuperHeader()
        numberOfFiles = ReadLeInt16()
        thisMethod = ReadLeByte()
        If Method <> ZipConstants.DEFLATE AndAlso Method <> ZipConstants.GZIP Then
            Throw New ArgumentOutOfRangeException()
        End If
    End Sub 'ReadSuperHeader

    Private Function ReadBuf(ByVal outBuf() As Byte, ByVal length As Integer) As Integer
        Return baseStream.Read(outBuf, 0, length)
    End Function 'ReadBuf

    ' 从 baseStream 读取一个字节。
    Private Function ReadLeByte() As Byte
        Return System.Convert.ToByte(baseStream.ReadByte() And &HFF)
    End Function 'ReadLeByte

    ' 以小尾序(Little-Endian)字节顺序来读取一个不带符号的 short 基础数据流。
    Private Function ReadLeInt16() As Int16
        Dim i As Int16 = CType(ReadLeByte(), Int16)
        Dim j As Int16 = CType(ReadLeByte(), Int16)
        Return (i Or (j << 8))
    End Function 'ReadLeInt16

    ' 以小尾序(Little-Endian)字节顺序来读取一个 int 基底数据流。
    Private Function ReadLeInt32() As Int32
        Dim ui As Int32
        Dim uj As Int32
        ui = CType(ReadLeInt16(), Int32)
        uj = CType(ReadLeInt16(), Int32)
        If (ui < 0) Then
            ui = System.Math.Pow(2, 16) + ui
        End If
        Return (ui Or (uj << 16))
    End Function 'ReadLeInt32


    Private Function ConvertToString(ByVal data() As Byte) As String
        Return System.Text.Encoding.ASCII.GetString(data, 0, data.Length)
    End Function 'ConvertToString


    ' 从压缩文件读取下一个项目并返回其描述。
    Private Function GetNextEntry() As ZipEntry
        Dim currentEntry As ZipEntry = Nothing
        Try
            Dim size As Int32 = ReadLeInt32()
            If size = -1 Then
                Return New ZipEntry(String.Empty)
            End If
            Dim csize As Int32 = ReadLeInt32()
            Dim crc(15) As Byte
            ReadBuf(crc, crc.Length)

            Dim dostime As Int32 = ReadLeInt32()
            Dim nameLength As Int16 = ReadLeInt16()

            Dim buffer(nameLength - 1) As Byte
            ReadBuf(buffer, nameLength)
            Dim name As String = ConvertToString(buffer)

            currentEntry = New ZipEntry(name)
            currentEntry.Size = size
            currentEntry.CompressedSize = csize
            currentEntry.SetCrc(crc)
            currentEntry.DosTime = dostime
        Catch ex As ArgumentException
            ZipConstants.ShowError(ZipConstants.ArgumentError)
        Catch ex As ObjectDisposedException
            ZipConstants.ShowError(ZipConstants.CloseError)
        End Try
        Return currentEntry
    End Function 'GetNextEntry

    ' 将未压缩数据写入项目中的文件名称。
    ' 它会初始化一个内存数据流来作为暂存处,并且使用 Gzip 数据流
    ' 或 Deflate 数据流来解压缩它。
    Private Sub WriteUncompressedFile(ByVal entry As ZipEntry, ByVal completePath As String)
        Dim ms As New MemoryStream()
        Try
            Dim b(entry.CompressedSize - 1) As Byte
            baseStream.Read(b, 0, CType(entry.CompressedSize, Integer))
            If CheckCRC(entry.GetCrc(), b) Then
                ms.Write(b, 0, b.Length)
            End If
            ms.Seek(0, SeekOrigin.Begin)
            If Method = ZipConstants.DEFLATE Then
                zipStream = New DeflateStream(ms, CompressionMode.Decompress, False)
            ElseIf Method = ZipConstants.GZIP Then
                zipStream = New GZipStream(ms, CompressionMode.Decompress, False)
            End If

            Dim index As Integer = entry.Name.LastIndexOf(ZipConstants.BackSlash)
            Dim name As String = completePath + entry.Name.Substring(index + 1)
            Dim rewrite As New FileStream(name, FileMode.Create)
            b = New Byte(entry.Size - 1) {}
            zipStream.Read(b, 0, CType(entry.Size, Integer))

            rewrite.Write(b, 0, CType(entry.Size, Integer))
            rewrite.Close()
        Catch ex As IOException
            ZipConstants.ShowError(ZipConstants.IOError)
        Catch ex As ArgumentException
            ZipConstants.ShowError(ZipConstants.ArgumentError)
        Finally
            zipStream.Close()
            ms.Close()
        End Try
    End Sub 'WriteUncompressedFile


    ' 解压缩清单中的所有项目。
    ' 清单可能是空的。
    Public Sub ExtractAll(ByVal zipEntries As List(Of ZipEntry), _
                    ByVal startPath As String)
        Try
            Dim dir As New DirectoryInfo(startPath + zipName)
            If Not dir.Exists Then
                dir.Create()
            End If
            Dim jump As Integer = 3
            baseStream.Seek(jump, SeekOrigin.Begin)

            Dim entry As ZipEntry
            For Each entry In zipEntries
                Dim index1 As Integer = entry.Name.IndexOf(ZipConstants.BackSlash)
                Dim index2 As Integer = entry.Name.LastIndexOf(ZipConstants.BackSlash)
                Dim relPath As String = entry.Name.Substring(index1 + 1, index2 - index1)
                If index1 = 0 Then
                    relPath = String.Empty
                End If
                If relPath.Length <> 0 Then
                    dir.CreateSubdirectory(relPath)
                End If
                jump = ZipConstants.FixedHeaderSize + entry.NameLength
                baseStream.Seek(jump, SeekOrigin.Current)
                WriteUncompressedFile(entry, startPath + zipName + ZipConstants.BackSlash + relPath)
            Next entry
            CH2_DemoForm002.statusMessage = String.Format(System.Threading.Thread.CurrentThread.CurrentUICulture, ZipConstants.ExtractMessage, startPath + zipName + ZipConstants.BackSlash)
        Catch ex As IOException
            ZipConstants.ShowError(ZipConstants.IOError)
        Catch ex As OutOfMemoryException
            ZipConstants.ShowError(ZipConstants.MemoryError)
        End Try
    End Sub

    ' 解压缩指定的项目。
    Public Sub Extract(ByVal entry As ZipEntry, ByVal jump As Long, ByVal startPath As String)
        Try
            Dim dir As New DirectoryInfo(startPath + zipName)
            If Not dir.Exists Then
                dir.Create()
            End If
            Dim index1 As Integer = entry.Name.IndexOf(ZipConstants.BackSlash)
            Dim index2 As Integer = entry.Name.LastIndexOf(ZipConstants.BackSlash)
            Dim relPath As String = entry.Name.Substring(index1 + 1, index2 - index1)
            If index1 = 0 Then
                relPath = String.Empty
            End If
            If relPath.Length <> 0 Then
                dir.CreateSubdirectory(relPath)
            End If
            baseStream.Seek(jump, SeekOrigin.Begin)
            jump = ZipConstants.FixedHeaderSize + entry.NameLength
            baseStream.Seek(jump, SeekOrigin.Current)

            WriteUncompressedFile(entry, startPath + zipName + ZipConstants.BackSlash + relPath)
            CH2_DemoForm002.statusMessage = String.Format(System.Threading.Thread.CurrentThread.CurrentUICulture, ZipConstants.ExtractMessage, startPath + zipName + ZipConstants.BackSlash)
        Catch ex As IOException
            ZipConstants.ShowError(ZipConstants.IOError)
        Catch ex As OutOfMemoryException
            ZipConstants.ShowError(ZipConstants.MemoryError)
        End Try
    End Sub

    ' 取得文件中的所有项目。
    Public Function GetAllEntries() As List(Of ZipEntry)
        Dim headers As List(Of ZipEntry)
        headers = Nothing
        Try
            If thisMethod = 255 OrElse numberOfFiles = -1 Then
                baseStream.Seek(0, SeekOrigin.Begin)
                ReadSuperHeader()
            End If
            headers = New List(Of ZipEntry)(numberOfFiles)
            baseStream.Seek(3, SeekOrigin.Begin)
            Dim i As Integer

            While i < numberOfFiles
                Dim entry As ZipEntry = GetNextEntry()
                headers.Add(entry)
                baseStream.Seek(entry.CompressedSize, SeekOrigin.Current)
                i += 1
            End While
        Catch ex As IOException
            ZipConstants.ShowError(ZipConstants.IOError)
        End Try

        Return headers
    End Function


    ' 取得封存档的压缩方式。
    Public ReadOnly Property Method() As Byte
        Get
            Return thisMethod
        End Get
    End Property '更多.net源码和教程,来自[乐博网 www.lob.cn]

    ' 检查字节数组的 CRC。
    Private Function CheckCRC(ByVal crc As Byte(), ByVal data As Byte()) As Boolean
        Dim newCrc As Byte() = md5.ComputeHash(data)
        Dim i As Integer

        While i < crc.Length
            If crc(i) <> newCrc(i) Then
                Return False
            End If
            i += 1
        End While
        Return True
    End Function 'CheckCRC
End Class 'ZipReader


阅读(779) | 评论(0) | 转发(0) |
0

上一篇:.Net经典压缩类3

下一篇:.Net经典压缩类4

给主人留下些什么吧!~~