zlib 包

介绍

提供流式压缩和解压功能,支持从输入流读取数据,将其压缩或解压,并写入字节数组,或从字节数组中读取数据,将其压缩或解压,并写入输出流。

压缩和解压使用自研 deflate 算法,压缩和解压数据格式支持 gzip 格式和 deflate raw 格式。

压缩时可指定压缩等级,支持默认快速、默认、高压缩率三个等级,压缩速度依次下降,压缩率依次提升。

主要接口

enum WrapType

public enum WrapType {
    | DeflateFormat
    | GzipFormat
}

该枚举类用于表示压缩数据格式,目前支持 DeflateFormatGzipFormat两种格式。

DeflateFormat

DeflateFormat

功能:构造一个表示 Deflate 压缩数据格式的枚举实例。

GzipFormat

GzipFormat

功能:构造一个表示 Gzip 压缩数据格式的枚举实例。

enum CompressLevel

public enum CompressLevel {
    | BestSpeed
    | DefaultCompression
    | BestCompression
}

该枚举类用于表示压缩等级,压缩等级决定了压缩率和压缩速度,目前支持三种压缩等级,压缩率由小到大,压缩速度由快到慢依次为:BestSpeedDefaultCompressionBestCompression

BestSpeed

BestSpeed             

功能:构造一个压缩等级枚举实例,表示压缩速度最快,压缩率相对较低。

DefaultCompression

DefaultCompression

功能:构造一个压缩等级枚举实例,表示默认压缩等级。

BestCompression

BestCompression

功能:构造一个压缩等级枚举实例,表示压缩率最高,压缩速度相对降低。

class CompressInputStream

public class CompressInputStream <: InputStream {
    public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}

该类实现了一个压缩输入流。可将其绑定到指定的 InputStream 类型输入流,读取、压缩其中的数据,并将压缩后数据输出到指定字节数组。

init

public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)

功能:构造一个压缩输入流。需绑定一个输入流,可设置压缩数据格式、压缩等级、内部缓冲区大小(每次从输入流中读取多少数据进行压缩)。

参数:

  • inputStream:待压缩的输入流
  • wrap:压缩数据格式,默认值为 DeflateFormat
  • compressLevel:压缩等级,默认值为 DefaultCompression
  • bufLen:输入流缓冲区的大小,默认 512 字节

异常:

  • ZlibException:如果 bufLen 小于等于 0,输入流分配内存失败,或压缩资源初始化失败,抛出异常

func read

public func read(outBuf: Array<Byte>): Int64

功能:从绑定的输入流中读取数据并压缩,压缩后数据放入指定的字节数组中。

参数:

  • outBuf:用来存放压缩后数据的缓冲区

返回值:如果压缩成功,返回压缩后字节数,如果绑定的输入流中数据已经全部压缩完成,或者该压缩输入流被关闭,返回 0

异常:

  • ZlibException:当 outBuf 为空,或压缩数据失败,抛出异常

func close

public func close(): Unit

功能:关闭压缩输入流。当前 CompressInputStream 实例使用完毕后必须调用此接口来释放其所占内存资源,以免造成内存泄漏。调用该函数前需确保 read 函数已返回 0,否则可能导致绑定的 InputStream 并未被全部压缩。

异常:

  • ZlibException:如果释放压缩资源失败,抛出异常

class CompressOutputStream

public class CompressOutputStream <: OutputStream {
    public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)
}

该类实现了一个压缩输出流。可将其绑定到指定的 OutputStream 类型输出流,读取、压缩指定字节数组中的数据,并将压缩后数据输出到绑定的输出流。

init

public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, compressLevel!: CompressLevel = DefaultCompression, bufLen!: Int64 = 512)

功能:构造一个压缩输出流,需绑定一个输出流,可设置压缩数据类型、压缩等级、内部缓冲区大小(每得到多少压缩后数据往输出流写一次)

参数:

  • outputStream:绑定的输出流,压缩后数据将写入该输出流
  • wrap:压缩数据格式,默认值为 DeflateFormat
  • compressLevel:压缩等级,默认值为 DefaultCompression
  • bufLen:输出流缓冲区的大小,默认 512 字节

异常:

  • ZlibException:如果 bufLen 小于等于 0,输出流分配内存失败,或压缩资源初始化失败,抛出异常

func write

public func write(inBuf: Array<Byte>): Unit

功能:将指定字节数组中的数据进行压缩,并写入输出流,当数据全部压缩完成并写入输出流,函数返回。

参数:

  • inBuf:待压缩的字节数组

异常:

  • ZlibException:如果当前压缩输出流已经被关闭,或压缩数据失败,抛出异常

func flush

public func flush(): Unit

功能:刷新压缩输出流。将内部缓冲区里已压缩的数据刷出并写入绑定的输出流,然后刷新绑定的输出流。

异常:

  • ZlibException:如果当前压缩输出流已经被关闭,抛出异常

func close

public func close(): Unit

功能:关闭当前压缩输出流实例。写入剩余压缩数据(包括缓冲区中数据,以及压缩尾部信息),并释放其所占内存资源。当前压缩输出流使用完毕后必须调用此接口来释放其所占内存资源,以免造成内存泄漏。在调用 close 函数前,绑定的输出流里已写入的数据并不是一段完整的压缩数据,调用 close 函数后,才会把剩余压缩数据写入绑定的输出流,使其完整。

异常:

  • ZlibException:如果当前压缩输出流已经被关闭,或释放压缩资源失败,抛出异常

class DecompressInputStream

public class DecompressInputStream <: InputStream {
    public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}

该类实现了一个解压输入流。可将其绑定到指定的 InputStream 类型输入流,读取、解压其中的数据,并将解压后数据输出到指定字节数组。

init

public init(inputStream: InputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)

功能:构造一个解压输入流。需绑定一个输入流,可设置待解压数据格式、内部缓冲区大小(每次从输入流中读取多少数据进行解压)。

参数:

  • inputStream:待压缩的输入流
  • wrap:待解压数据格式,默认值为 DeflateFormat
  • bufLen:输入流缓冲区的大小,默认 512 字节

异常:

  • ZlibException:如果 bufLen 小于等于 0,输入流分配内存失败,或待解压资源初始化失败,抛出异常

func read

public func read(outBuf: Array<Byte>): Int64

功能:从绑定的输入流中读取数据并解压,解压后数据放入指定的字节数组中。

参数:

  • outBuf:用来存放解压后数据的缓冲区

返回值:如果解压成功,返回解压后字节数,如果绑定的输入流中数据已经全部解压完成,或者该解压输入流被关闭,返回 0

异常:

  • ZlibException:当 outBuf 为空,或解压数据失败,抛出异常

func close

public func close(): Unit

功能:关闭解压输入流。当前 DecompressInputStream 实例使用完毕后必须调用此接口来释放其所占内存资源,以免造成内存泄漏。调用该函数前需确保 read 函数已返回 0,否则可能导致绑定的 InputStream 并未被全部解压。

异常:

  • ZlibException,如果释放解压资源失败,抛出异常

class DecompressOutputStream

public class DecompressOutputStream <: OutputStream {
    public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)
}

该类实现了一个解压输出流。可将其绑定到指定的 OutputStream 类型输出流,读取、解压指定字节数组中的数据,并将解压后数据输出到绑定的输出流。

init

public init(outputStream: OutputStream, wrap!: WrapType = DeflateFormat, bufLen!: Int64 = 512)

功能:构造一个解压输出流,需绑定一个输出流,可设置压缩数据类型、压缩等级、内部缓冲区大小(解压后数据会存入内部缓冲区,缓冲区存满后再写到输出流)。

参数:

  • outputStream:绑定的输出流,解压后数据将写入该输出流
  • wrap:待解压数据格式,默认值为 DeflateFormat
  • bufLen:输出流缓冲区的大小,默认 512 字节

异常:

  • ZlibException:如果 bufLen 小于等于 0,输出流分配内存失败,或解压资源初始化失败,抛出异常

func write

public func write(inBuf: Array<Byte>): Unit

功能:将指定字节数组中的数据进行解压,并写入输出流,当数据全部解压完成并写入输出流,函数返回。

参数:

  • inBuf:待解压的字节数组

异常:

  • ZlibException:如果当前解压输出流已经被关闭,或解压数据失败,抛出异常

func flush

public func flush(): Unit

功能:刷新解压输出流。将内部缓冲区里已解压的数据刷出并写入绑定的输出流,然后刷新绑定的输出流。

异常:

  • ZlibException:如果当前解压输出流已经被关闭,抛出异常

func close

public func close(): Unit

功能:关闭当前解压输出流实例。写入剩余解压后数据,并释放其所占内存资源。当前压缩输出流使用完毕后必须调用此接口来释放其所占内存资源,以免造成内存泄漏。如果之前 write 函数已处理的压缩数据不完整,调用 close 函数时会因为解压数据不全而抛出异常。

异常:

  • ZlibException:如果当前压缩输出流已经被关闭,通过 write 函数传入的待解压数据不完整,或释放压缩资源失败,抛出异常

class ZlibException

public class ZlibException <: Exception {
    public init(message: String)
}

zlib 包的异常类。

init

public init(message: String)

功能:创建 ZlibException 实例。

参数:

  • message:异常提示信息

示例

Gzip 格式数据的压缩和解压

from compress import zlib.*
from std import fs.*

main() {
    var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
    File.writeTo("./zlib.txt", arr, openOption: Create(false))

    if (compressFile("./zlib.txt", "./zlib_copmressed.zlib") <= 0) {
        println("Failed to compress file!")
    }

    if (decompressFile("./zlib_copmressed.zlib", "./zlib_decopmressed.txt") != arr.size) {
        println("Failed to decompress file!")
    }

    if (compareFile("./zlib.txt", "./zlib_decopmressed.txt")) {
        println("success")
    } else {
        println("failed")
    }

    File.delete("./zlib.txt")
    File.delete("./zlib_copmressed.zlib")
    File.delete("./zlib_decopmressed.txt")
    return 0
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
    var destFile: File = File(destFileName, OpenOption.Create(false))

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func decompressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
    var destFile: File = File(destFileName, OpenOption.Create(false))

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
    var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: GzipFormat, bufLen: 10000)
    while (true) {
        var readNum = decompressInputStream.read(tempBuf)
        if (readNum <= 0) {
            break
        }
        destFile.write(tempBuf.slice(0, readNum).toArray())
        count += readNum
    }
    decompressInputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func compareFile(fileName1: String, fileName2: String): Bool {
    return File.readFrom(fileName1) == File.readFrom(fileName2)
}

运行结果:

success

Deflate 格式数据的压缩和解压

from compress import zlib.*
from std import fs.*

main() {
    var arr: Array<Byte> = Array<Byte>(1024 * 1024, {i => UInt8(i % 256)})
    File.writeTo("./zlib1.txt", arr, openOption: Create(false))

    if (compressFile("./zlib1.txt", "./zlib_copmressed1.zlib") <= 0) {
        println("Failed to compress file!")
    }

    if (decompressFile("./zlib_copmressed1.zlib", "./zlib_decopmressed1.txt") != arr.size) {
        println("Failed to decompress file!")
    }

    if (compareFile("./zlib1.txt", "./zlib_decopmressed1.txt")) {
        println("success")
    } else {
        println("failed")
    }

    File.delete("./zlib1.txt")
    File.delete("./zlib_copmressed1.zlib")
    File.delete("./zlib_decopmressed1.txt")
    return 0
}

func compressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
    var destFile: File = File(destFileName, OpenOption.Create(false))

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
    var compressOutputStream: CompressOutputStream = CompressOutputStream(destFile, wrap: DeflateFormat)
    while (true) {
        var readNum = srcFile.read(tempBuf)
        if (readNum > 0) {
            compressOutputStream.write(tempBuf.slice(0, readNum).toArray())
            count += readNum
        } else {
            break
        }
    }
    compressOutputStream.flush()
    compressOutputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func decompressFile(srcFileName: String, destFileName: String): Int64 {
    var count: Int64 = 0
    var srcFile: File = File(srcFileName, OpenOption.Open(true, false))
    var destFile: File = File(destFileName, OpenOption.Create(false))

    var tempBuf: Array<UInt8> = Array<UInt8>(1024, item: 0)
    var decompressInputStream: DecompressInputStream = DecompressInputStream(srcFile, wrap: DeflateFormat)
    while (true) {
        var readNum = decompressInputStream.read(tempBuf)
        if (readNum <= 0) {
            break
        }
        destFile.write(tempBuf.slice(0, readNum).toArray())
        count += readNum
    }
    decompressInputStream.close()

    srcFile.close()
    destFile.close()
    return count
}

func compareFile(fileName1: String, fileName2: String): Bool {
    return File.readFrom(fileName1) == File.readFrom(fileName2)
}

运行结果

success